Skip to content

Commit

Permalink
Merge pull request #394 from graasp/328/addPasswordEdition
Browse files Browse the repository at this point in the history
328/addPasswordEdition
  • Loading branch information
victorggonzalez authored Jul 15, 2022
2 parents c1bb197 + d4205d5 commit c2007ff
Show file tree
Hide file tree
Showing 12 changed files with 431 additions and 23 deletions.
81 changes: 79 additions & 2 deletions cypress/integration/memberProfile.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import {
MEMBER_PROFILE_LANGUAGE_SWITCH_ID,
MEMBER_PROFILE_INSCRIPTION_DATE_ID,
MEMBER_PROFILE_MEMBER_ID_COPY_BUTTON_ID,
USER_NEW_PASSWORD_INPUT_ID,
USER_CONFIRM_PASSWORD_INPUT_ID,
USER_CURRENT_PASSWORD_INPUT_ID,
CONFIRM_CHANGE_PASSWORD_BUTTON_ID,
} from '../../src/config/selectors';
import { CURRENT_USER } from '../fixtures/members';
import { formatDate } from '../../src/utils/date';
Expand Down Expand Up @@ -34,6 +38,10 @@ describe('Member Profile', () => {
'contain',
langs[extra.lang],
);
cy.get(`#${USER_CURRENT_PASSWORD_INPUT_ID}`).should('be.visible');
cy.get(`#${USER_NEW_PASSWORD_INPUT_ID}`).should('be.visible');
cy.get(`#${USER_CONFIRM_PASSWORD_INPUT_ID}`).should('be.visible');
cy.get(`#${CONFIRM_CHANGE_PASSWORD_BUTTON_ID}`).should('be.visible');
});

it('Changing Language edits user', () => {
Expand All @@ -46,12 +54,81 @@ describe('Member Profile', () => {
expect(body?.extra?.lang).to.equal('en');
});
});

it('Copy member ID to clipboard', () => {
const { id } = CURRENT_USER;

cy.get(`#${MEMBER_PROFILE_MEMBER_ID_COPY_BUTTON_ID}`).click();

cy.get('@copy').should('be.calledWithExactly', id);
});

it('Throw error with empty password', () => {

cy.get(`#${USER_NEW_PASSWORD_INPUT_ID}`).type('password1');

cy.get(`#${CONFIRM_CHANGE_PASSWORD_BUTTON_ID}`).click();
cy.get('#confirmPasswordInput-helper-text').should('be.visible');
cy.get(`#${USER_NEW_PASSWORD_INPUT_ID}`).clear();
cy.get('#newPasswordInput-helper-text').should('be.visible');
});

it('Not trigger request with same current password', () => {
Cypress.on('fail', (error) => {
if (error.message.indexOf('Timed out retrying') !== 0) throw error
})

cy.get(`#${USER_CURRENT_PASSWORD_INPUT_ID}`).type('password1');
cy.get(`#${USER_NEW_PASSWORD_INPUT_ID}`).type('password1');

cy.get(`#${CONFIRM_CHANGE_PASSWORD_BUTTON_ID}`).click();
cy.wait('@updatePassword', {
requestTimeout: 1000,
}).then((xhr) => {
expect.isNull(xhr.response.body);
}); });

it('Not trigger request with diffferent passwords', () => {
Cypress.on('fail', (error) => {
if (error.message.indexOf('Timed out retrying') !== 0) throw error
})

cy.get(`#${USER_NEW_PASSWORD_INPUT_ID}`).type('password1');
cy.get(`#${USER_CONFIRM_PASSWORD_INPUT_ID}`).type('password2');

cy.get(`#${CONFIRM_CHANGE_PASSWORD_BUTTON_ID}`).click();
cy.wait('@updatePassword', {
requestTimeout: 1000,
}).then((xhr) => {
expect.isNull(xhr.response.body);
});
});

it('Not trigger request with weak password', () => {
Cypress.on('fail', (error) => {
if (error.message.indexOf('Timed out retrying') !== 0) throw error
})

cy.get(`#${USER_NEW_PASSWORD_INPUT_ID}`).type('password');
cy.get(`#${USER_CONFIRM_PASSWORD_INPUT_ID}`).type('password');

cy.get(`#${CONFIRM_CHANGE_PASSWORD_BUTTON_ID}`).click();
cy.wait('@updatePassword', {
requestTimeout: 1000,
}).then((xhr) => {
expect.isNull(xhr.response.body);
});
});

it('Update user password correctly', () => {

cy.get(`#${USER_NEW_PASSWORD_INPUT_ID}`).type('ASDasd123');
cy.get(`#${USER_CONFIRM_PASSWORD_INPUT_ID}`).type('ASDasd123');

cy.get(`#${CONFIRM_CHANGE_PASSWORD_BUTTON_ID}`).click();
cy.wait('@updatePassword').then(({ request: { body } }) => {
expect(body?.currentPassword).to.equal('');
expect(body?.password).to.equal('ASDasd123');
});
});
});
4 changes: 4 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import {
mockPatchInvitation,
mockDeleteInvitation,
mockPublishItem,
mockUpdatePassword,
mockPostManyItemMemberships,
} from './server';
import './commands/item';
Expand Down Expand Up @@ -150,6 +151,7 @@ Cypress.Commands.add(
getItemInvitationsError = false,
patchInvitationError = false,
deleteInvitationError = false,
updatePasswordError = false,
} = {}) => {
const cachedItems = JSON.parse(JSON.stringify(items));
const cachedMembers = JSON.parse(JSON.stringify(members));
Expand Down Expand Up @@ -305,6 +307,8 @@ Cypress.Commands.add(
mockDeleteInvitation(items, deleteInvitationError);

mockPublishItem(items);

mockUpdatePassword(members, updatePasswordError);
},
);

Expand Down
19 changes: 18 additions & 1 deletion cypress/support/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ const {
buildDeleteInvitationRoute,
buildPatchInvitationRoute,
buildResendInvitationRoute,
buildItemPublishRoute,
buildItemPublishRoute,
buildUpdateMemberPassword
} = API_ROUTES;

const API_HOST = Cypress.env('API_HOST');
Expand Down Expand Up @@ -1603,3 +1604,19 @@ export const mockPublishItem = (items) => {
},
).as('publishItem');
};

export const mockUpdatePassword = (members, shouldThrowError) => {
cy.intercept(
{
method: DEFAULT_PATCH.method,
url: new RegExp(`${API_HOST}/${buildUpdateMemberPassword}`),
},
({ reply }) => {
if (shouldThrowError) {
return reply({ statusCode: StatusCodes.BAD_REQUEST });
}

return reply('update password');
},
).as('updatePassword');
};
13 changes: 9 additions & 4 deletions src/components/member/AvatarSetting.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ import {
import { MEMBER_PROFILE_AVATAR_UPLOAD_BUTTON_CLASSNAME } from '../../config/selectors';
import StatusBar from '../file/StatusBar';

const useStyles = makeStyles(() => ({
const useStyles = makeStyles((theme) => ({
thumbnail: {
textAlign: 'right',
},
mainContainer: {
flexDirection: 'column',
alignItems: 'flex-start',
margin: theme.spacing(1, 0),
},
}));

const AvatarSetting = ({ user }) => {
Expand Down Expand Up @@ -109,10 +114,10 @@ const AvatarSetting = ({ user }) => {
{uppy && (
<StatusBar uppy={uppy} handleClose={handleClose} open={openStatusBar} />
)}
<Grid container justifyContent="space-between">
<Grid container spacing={3} className={classes.mainContainer}>
<Grid item sm={6}>
<Typography variant="h5">{t('Thumbnail')}</Typography>
<Typography variant="body">{t('Update thumbnail')}</Typography>
<Typography variant="body1">{t('Update thumbnail')}</Typography>
<input
type="file"
accept="image/*"
Expand All @@ -123,7 +128,7 @@ const AvatarSetting = ({ user }) => {
className={MEMBER_PROFILE_AVATAR_UPLOAD_BUTTON_CLASSNAME}
/>
</Grid>
<Grid item sm={6} className={classes.thumbnail}>
<Grid item sm={6} xs={12}>
<Avatar
id={userId}
extra={user?.get('extra')}
Expand Down
56 changes: 44 additions & 12 deletions src/components/member/DeleteMemberDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import { Grid, Typography } from '@material-ui/core';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { makeStyles } from '@material-ui/core/styles';
Expand All @@ -15,12 +16,26 @@ import {
DELETE_MEMBER_BUTTON_ID,
} from '../../config/selectors';

const useStyles = makeStyles(() => ({
const useStyles = makeStyles((theme) => ({
confirmDeleteButton: {
color: 'red',
},
deleteButton: {
color: 'red',
backgroundColor: 'red',
margin: theme.spacing(1, 0),
},
mainContainer: {
flexDirection: 'column',
alignItems: 'flex-start',
margin: theme.spacing(1, 0),
},
deleteAccountContainer: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'flex-start',
padding: theme.spacing(0, 1),
margin: theme.spacing(0, 0),
},
}));

Expand Down Expand Up @@ -64,16 +79,33 @@ const DeleteMemberDialog = ({ id }) => {
</Button>
</DialogActions>
</Dialog>

<Button
id={DELETE_MEMBER_BUTTON_ID}
variant="text"
className={classes.deleteButton}
color="secondary"
onClick={() => setOpen(true)}
>
{t('Delete Account')}
</Button>
<Grid container spacing={3} className={classes.mainContainer}>
<Grid item xs={8}>
<Grid item xs={12}>
<Typography variant="h5">{t('Delete this account')}</Typography>
</Grid>
<Grid
container
spacing={3}
className={classes.deleteAccountContainer}
>
<Button
id={DELETE_MEMBER_BUTTON_ID}
variant="contained"
className={classes.deleteButton}
color="primary"
onClick={() => setOpen(true)}
>
{t('Delete Account')}
</Button>
<Typography variant="caption">
{t(
'Once you delete an account, there is no going back. Please be certain.',
)}
</Typography>
</Grid>
</Grid>
</Grid>
</>
);
};
Expand Down
2 changes: 2 additions & 0 deletions src/components/member/MemberProfileScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Main from '../main/Main';
import { CurrentUserContext } from '../context/CurrentUserContext';
import AvatarSetting from './AvatarSetting';
import DeleteMemberDialog from './DeleteMemberDialog';
import PasswordSetting from './PasswordSetting';

const useStyles = makeStyles((theme) => ({
root: {
Expand Down Expand Up @@ -131,6 +132,7 @@ const MemberProfileScreen = () => {
</Grid>

<AvatarSetting user={member} />
<PasswordSetting user={member} />
<DeleteMemberDialog id={member?.get('id')} />
</Card>
</Main>
Expand Down
Loading

0 comments on commit c2007ff

Please sign in to comment.