E2e tests for mfa. Fix a bug that made mfa impossible to disable

This commit is contained in:
SleepWalker 2019-12-29 16:20:08 +02:00
parent 73d2baeb3a
commit f8670db315
7 changed files with 242 additions and 7 deletions

View File

@ -38,9 +38,12 @@ export default class MfaDisable extends React.Component<
onSubmit = (form: FormModel) => {
return this.props
.onSubmit(form, () => {
const { totp } = form.serialize() as { totp: string };
const { totp, password } = form.serialize() as {
totp: string;
password?: string;
};
return disableMFA(this.context.userId, totp);
return disableMFA(this.context.userId, totp, password);
})
.then(() => this.props.onComplete())
.catch(resp => {

View File

@ -77,7 +77,11 @@ const linksByOs: {
export default function OsInstruction({ os }: { os: OS }) {
return (
<div className={styles.osInstruction}>
<div
className={styles.osInstruction}
data-testid="os-instruction"
data-os={os}
>
<h3 className={styles.instructionTitle}>
<Message {...messages.installOnOfTheApps} />
</h3>

View File

@ -15,7 +15,11 @@ export default function OsInstruction({
onClick: (event: React.MouseEvent<any>) => void;
}) {
return (
<div className={clsx(styles.osTile, className)} onClick={onClick}>
<div
className={clsx(styles.osTile, className)}
onClick={onClick}
data-testid="os-tile"
>
<img className={styles.osLogo} src={logo} alt={label} />
<div className={styles.osName}>{label}</div>
</div>

View File

@ -40,7 +40,9 @@ export default function KeyForm({
</div>
<div className={profileForm.formRow}>
<div className={styles.key}>{formattedSecret}</div>
<div className={styles.key} data-testid="secret">
{formattedSecret}
</div>
</div>
<div className={profileForm.formRow}>

View File

@ -48,4 +48,42 @@ describe('Profile — Change password', () => {
cy.location('pathname').should('eq', '/');
});
});
it('should close password popup if form has errors', () => {
cy.login({ accounts: ['default'] }).then(({ accounts: [account] }) => {
cy.server();
cy.route({
method: 'POST',
url: `/api/v1/accounts/${account.id}/password`,
response: {
success: false,
errors: {
password: 'force popup to be shown',
},
},
}).as('password');
cy.visit('/');
openSectionByName('Password');
cy.location('pathname').should('eq', '/profile/change-password');
cy.get('[name=newPassword]').type(account.password);
// make a mistake to hide confirm popup in future
cy.get('[name=newRePassword]').type(`${account.password}lol`);
cy.get('[name=logoutAll]').should('be.checked');
cy.get('[type=submit]').click();
// disable response mocks
cy.route({
method: 'POST',
url: `/api/v1/accounts/${account.id}/password`,
}).as('password');
confirmWithPassword(account.password);
cy.getByTestId('password-request-form').should('not.be.visible');
cy.contains('The passwords does not match').should('be.visible');
});
});
});

View File

@ -0,0 +1,182 @@
import {
openSectionByName,
getSectionByName,
confirmWithPassword,
} from './utils';
describe('Profile — mfa', () => {
it('should enable mfa', () => {
const totp = 'totp123';
cy.login({ accounts: ['default'] }).then(({ accounts: [account] }) => {
cy.server();
cy.route({
method: 'POST',
url: `/api/v1/accounts/${account.id}/two-factor-auth`,
response: { success: false, errors: { password: 'foo' } },
}).as('mfaSaved');
cy.visit('/');
getSectionByName('Twofactor auth').should('contain', 'Disabled');
openSectionByName('Twofactor auth');
cy.location('pathname').should('eq', '/profile/mfa');
assertOs('Google Play', 'android');
assertOs('App Store', 'ios');
assertOs('Windows Store', 'windows');
cy.contains('App has been installed').click();
cy.location('pathname').should('eq', '/profile/mfa/step2');
cy.getByTestId('secret').should('not.be.empty');
cy.contains('Ready').click();
cy.location('pathname').should('eq', '/profile/mfa/step3');
cy.get('[name=totp]').type(`${totp}{enter}`);
cy.wait('@mfaSaved')
.its('requestBody')
.should(
'eq',
new URLSearchParams({
totp,
password: '',
}).toString(),
);
cy.route({
method: 'POST',
url: `/api/v1/accounts/${account.id}/two-factor-auth`,
response: { success: true },
}).as('mfaSaved');
cy.route({
method: 'GET',
url: `/api/v1/accounts/${account.id}`,
response: {
id: 7,
uuid: '522e8c19-89d8-4a6d-a2ec-72ebb58c2dbe',
username: 'SleepWalker',
isOtpEnabled: true, // fake enabled mfa
registeredAt: 1475568334,
lang: 'en',
elyProfileLink: 'http://ely.by/u7',
email: 'danilenkos@auroraglobal.com',
isActive: true,
passwordChangedAt: 1476075696,
hasMojangUsernameCollision: true,
shouldAcceptRules: false,
},
});
confirmWithPassword(account.password);
cy.wait('@mfaSaved')
.its('requestBody')
.should(
'eq',
new URLSearchParams({
totp,
password: account.password,
}).toString(),
);
cy.location('pathname').should('eq', '/');
getSectionByName('Twofactor auth').should('contain', 'Enabled');
});
});
it('should disable mfa', () => {
const totp = 'totp123';
cy.login({ accounts: ['default'] }).then(({ accounts: [account] }) => {
cy.server();
cy.route({
method: 'GET',
url: `/api/v1/accounts/${account.id}`,
response: {
id: 7,
uuid: '522e8c19-89d8-4a6d-a2ec-72ebb58c2dbe',
username: 'SleepWalker',
isOtpEnabled: true, // fake enabled mfa
registeredAt: 1475568334,
lang: 'en',
elyProfileLink: 'http://ely.by/u7',
email: 'danilenkos@auroraglobal.com',
isActive: true,
passwordChangedAt: 1476075696,
hasMojangUsernameCollision: true,
shouldAcceptRules: false,
},
});
cy.route({
method: 'DELETE',
url: `/api/v1/accounts/${account.id}/two-factor-auth`,
response: { success: false, errors: { password: 'foo' } },
}).as('mfaSaved');
cy.visit('/');
getSectionByName('Twofactor auth').should('contain', 'Enabled');
openSectionByName('Twofactor auth');
cy.location('pathname').should('eq', '/profile/mfa');
cy.contains('Disable').click();
cy.get('[name=totp]').type(`${totp}{enter}`);
cy.wait('@mfaSaved')
.its('requestBody')
.should(
'eq',
new URLSearchParams({
totp,
password: '',
}).toString(),
);
cy.route({
method: 'DELETE',
url: `/api/v1/accounts/${account.id}/two-factor-auth`,
response: { success: true },
}).as('mfaSaved');
// unmock accounts route
cy.route({
method: 'GET',
url: `/api/v1/accounts/${account.id}`,
});
confirmWithPassword(account.password);
cy.wait('@mfaSaved')
.its('requestBody')
.should(
'eq',
new URLSearchParams({
totp,
password: account.password,
}).toString(),
);
cy.location('pathname').should('eq', '/');
getSectionByName('Twofactor auth').should('contain', 'Disabled');
});
});
});
function assertOs(name: string, os: string) {
cy.getByTestId('os-tile')
.contains(name)
.click();
cy.getByTestId('os-instruction').should('have.attr', 'data-os', os);
cy.getByTestId('os-tile')
.contains(name)
.click();
}

View File

@ -1,10 +1,12 @@
export function getSectionByName(name: string) {
return cy.getByTestId('profile-item').contains(name);
return cy
.getByTestId('profile-item')
.contains(name)
.closest('[data-testid="profile-item"]');
}
export function openSectionByName(name: string) {
return getSectionByName(name)
.closest('[data-testid="profile-item"]')
.getByTestId('profile-action')
.click();
}