mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-11-27 01:02:14 +05:30
Cover register and activation with e2e tests
This commit is contained in:
parent
f6f0aedc65
commit
c8b0168c69
@ -288,11 +288,9 @@ export default class AuthFlow implements AuthContext {
|
|||||||
* Tries to restore last oauth request, if it was stored in localStorage
|
* Tries to restore last oauth request, if it was stored in localStorage
|
||||||
* in last 2 hours
|
* in last 2 hours
|
||||||
*
|
*
|
||||||
* @api private
|
|
||||||
*
|
|
||||||
* @returns {bool} - whether oauth state is being restored
|
* @returns {bool} - whether oauth state is being restored
|
||||||
*/
|
*/
|
||||||
restoreOAuthState() {
|
private restoreOAuthState() {
|
||||||
if (/^\/(register|oauth2)/.test(this.getRequest().path)) {
|
if (/^\/(register|oauth2)/.test(this.getRequest().path)) {
|
||||||
// allow register or the new oauth requests
|
// allow register or the new oauth requests
|
||||||
return;
|
return;
|
||||||
|
@ -7,9 +7,10 @@ let sitekey;
|
|||||||
|
|
||||||
export type CaptchaID = string;
|
export type CaptchaID = string;
|
||||||
|
|
||||||
export default {
|
class Captcha {
|
||||||
/**
|
/**
|
||||||
* @param {DOMNode|string} el - dom node or id of element where to render captcha
|
* @param {DOMNode|string} el - dom node or id of element where to render captcha
|
||||||
|
* @param {object} options
|
||||||
* @param {string} options.skin - skin color (dark|light)
|
* @param {string} options.skin - skin color (dark|light)
|
||||||
* @param {Function} options.onSetCode - the callback, that will be called with
|
* @param {Function} options.onSetCode - the callback, that will be called with
|
||||||
* captcha verification code, after user successfully solves captcha
|
* captcha verification code, after user successfully solves captcha
|
||||||
@ -26,6 +27,9 @@ export default {
|
|||||||
onSetCode: (code: string) => void;
|
onSetCode: (code: string) => void;
|
||||||
},
|
},
|
||||||
): Promise<CaptchaID> {
|
): Promise<CaptchaID> {
|
||||||
|
// for testing purposes only
|
||||||
|
(window as any).e2eCaptchaSetCode = callback;
|
||||||
|
|
||||||
return this.loadApi().then(() =>
|
return this.loadApi().then(() =>
|
||||||
(window as any).grecaptcha.render(el, {
|
(window as any).grecaptcha.render(el, {
|
||||||
sitekey,
|
sitekey,
|
||||||
@ -33,14 +37,16 @@ export default {
|
|||||||
callback,
|
callback,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} captchaId - captcha id, returned from render promise
|
* @param {string} captchaId - captcha id, returned from render promise
|
||||||
*/
|
*/
|
||||||
reset(captchaId: CaptchaID) {
|
reset(captchaId: CaptchaID) {
|
||||||
|
delete (window as any).e2eCaptchaSetCode;
|
||||||
|
|
||||||
this.loadApi().then(() => (window as any).grecaptcha.reset(captchaId));
|
this.loadApi().then(() => (window as any).grecaptcha.reset(captchaId));
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {stirng} newLang
|
* @param {stirng} newLang
|
||||||
@ -49,7 +55,7 @@ export default {
|
|||||||
*/
|
*/
|
||||||
setLang(newLang: string) {
|
setLang(newLang: string) {
|
||||||
lang = newLang;
|
lang = newLang;
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} apiKey
|
* @param {string} apiKey
|
||||||
@ -58,14 +64,12 @@ export default {
|
|||||||
*/
|
*/
|
||||||
setApiKey(apiKey: string) {
|
setApiKey(apiKey: string) {
|
||||||
sitekey = apiKey;
|
sitekey = apiKey;
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api private
|
|
||||||
*
|
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
loadApi(): Promise<void> {
|
private loadApi(): Promise<void> {
|
||||||
if (!readyPromise) {
|
if (!readyPromise) {
|
||||||
readyPromise = Promise.all([
|
readyPromise = Promise.all([
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
@ -80,5 +84,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return readyPromise;
|
return readyPromise;
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
export default new Captcha();
|
||||||
|
@ -0,0 +1,145 @@
|
|||||||
|
it('should register', () => {
|
||||||
|
const username = `test${Date.now()}`;
|
||||||
|
const email = `${Date.now()}@gmail.com`;
|
||||||
|
const password = String(Date.now());
|
||||||
|
const captchaCode = 'captchaCode';
|
||||||
|
const activationKey = 'activationKey';
|
||||||
|
|
||||||
|
cy.server();
|
||||||
|
cy.route({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/signup',
|
||||||
|
response: {
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
}).as('signup');
|
||||||
|
cy.login({
|
||||||
|
accounts: ['default'],
|
||||||
|
updateState: false,
|
||||||
|
rawApiResp: true,
|
||||||
|
}).then(({ accounts: [account] }) => {
|
||||||
|
cy.route({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/signup/confirm',
|
||||||
|
response: account,
|
||||||
|
}).as('activate');
|
||||||
|
});
|
||||||
|
cy.visit('/');
|
||||||
|
|
||||||
|
cy.getByTestId('toolbar')
|
||||||
|
.contains('Join')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/register');
|
||||||
|
|
||||||
|
cy.get('[name=username]').type(username);
|
||||||
|
cy.get('[name=email]').type(email);
|
||||||
|
cy.get('[name=password]').type(password);
|
||||||
|
cy.get('[name=rePassword]').type(password);
|
||||||
|
cy.get('[name=rulesAgreement]').should('not.be.checked');
|
||||||
|
cy.get('[name=rulesAgreement]')
|
||||||
|
.parent()
|
||||||
|
.click();
|
||||||
|
cy.get('[name=rulesAgreement]').should('be.checked');
|
||||||
|
cy.window().should('have.property', 'e2eCaptchaSetCode');
|
||||||
|
cy.window().then(win => {
|
||||||
|
// fake captcha response
|
||||||
|
// @ts-ignore
|
||||||
|
win.e2eCaptchaSetCode(captchaCode);
|
||||||
|
});
|
||||||
|
cy.get('[type=submit]').click();
|
||||||
|
|
||||||
|
cy.wait('@signup')
|
||||||
|
.its('requestBody')
|
||||||
|
.should(
|
||||||
|
'eq',
|
||||||
|
new URLSearchParams({
|
||||||
|
email,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
rePassword: password,
|
||||||
|
rulesAgreement: '1',
|
||||||
|
lang: 'en',
|
||||||
|
captcha: captchaCode,
|
||||||
|
}).toString(),
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/activation');
|
||||||
|
|
||||||
|
cy.get('[name=key]').type(`${activationKey}{enter}`);
|
||||||
|
|
||||||
|
cy.wait('@activate')
|
||||||
|
.its('requestBody')
|
||||||
|
.should('eq', `key=${activationKey}`);
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow activation', () => {
|
||||||
|
const activationKey = 'activationKey';
|
||||||
|
|
||||||
|
cy.server();
|
||||||
|
cy.login({
|
||||||
|
accounts: ['default'],
|
||||||
|
updateState: false,
|
||||||
|
rawApiResp: true,
|
||||||
|
}).then(({ accounts: [account] }) => {
|
||||||
|
cy.route({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/signup/confirm',
|
||||||
|
response: account,
|
||||||
|
}).as('activate');
|
||||||
|
});
|
||||||
|
cy.visit('/register');
|
||||||
|
|
||||||
|
cy.getByTestId('auth-secondary-controls')
|
||||||
|
.contains('Already have')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/activation');
|
||||||
|
|
||||||
|
cy.get('[name=key]').type(`${activationKey}{enter}`);
|
||||||
|
|
||||||
|
cy.wait('@activate')
|
||||||
|
.its('requestBody')
|
||||||
|
.should('eq', `key=${activationKey}`);
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow resend code', () => {
|
||||||
|
const email = `${Date.now()}@gmail.com`;
|
||||||
|
const captchaCode = 'captchaCode';
|
||||||
|
|
||||||
|
cy.server();
|
||||||
|
cy.route({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/signup/repeat-message',
|
||||||
|
response: { success: true },
|
||||||
|
}).as('resend');
|
||||||
|
cy.visit('/register');
|
||||||
|
|
||||||
|
cy.getByTestId('auth-secondary-controls')
|
||||||
|
.contains('not received')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/resend-activation');
|
||||||
|
|
||||||
|
cy.get('[name=email]').type(email);
|
||||||
|
cy.window().should('have.property', 'e2eCaptchaSetCode');
|
||||||
|
cy.window().then(win => {
|
||||||
|
// fake captcha response
|
||||||
|
// @ts-ignore
|
||||||
|
win.e2eCaptchaSetCode(captchaCode);
|
||||||
|
});
|
||||||
|
cy.get('[type=submit]').click();
|
||||||
|
|
||||||
|
cy.wait('@resend')
|
||||||
|
.its('requestBody')
|
||||||
|
.should(
|
||||||
|
'eq',
|
||||||
|
new URLSearchParams({ email, captcha: captchaCode }).toString(),
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/activation');
|
||||||
|
});
|
@ -31,47 +31,56 @@ const accountsMap = {
|
|||||||
default2: account1,
|
default2: account1,
|
||||||
};
|
};
|
||||||
|
|
||||||
Cypress.Commands.add('login', async ({ accounts }) => {
|
Cypress.Commands.add(
|
||||||
const accountsData = await Promise.all(
|
'login',
|
||||||
accounts.map(async account => {
|
async ({ accounts, updateState = true, rawApiResp = false }) => {
|
||||||
let credentials;
|
const accountsData = await Promise.all(
|
||||||
|
accounts.map(async account => {
|
||||||
|
let credentials;
|
||||||
|
|
||||||
if (account) {
|
if (account) {
|
||||||
credentials = accountsMap[account];
|
credentials = accountsMap[account];
|
||||||
|
|
||||||
if (!credentials) {
|
if (!credentials) {
|
||||||
throw new Error(`Unknown account name: ${account}`);
|
throw new Error(`Unknown account name: ${account}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const resp = await fetch('/api/authentication/login', {
|
const resp = await fetch('/api/authentication/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||||
},
|
},
|
||||||
body: `${new URLSearchParams({
|
body: `${new URLSearchParams({
|
||||||
login: credentials.login,
|
login: credentials.login,
|
||||||
password: credentials.password,
|
password: credentials.password,
|
||||||
rememberMe: '1',
|
rememberMe: '1',
|
||||||
})}`,
|
})}`,
|
||||||
}).then(rawResp => rawResp.json());
|
}).then(rawResp => rawResp.json());
|
||||||
|
|
||||||
return {
|
if (rawApiResp) {
|
||||||
id: credentials.id,
|
return resp;
|
||||||
username: credentials.username,
|
}
|
||||||
email: credentials.email,
|
|
||||||
token: resp.access_token,
|
|
||||||
refreshToken: resp.refresh_token,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
const state = createState(accountsData);
|
return {
|
||||||
|
id: credentials.id,
|
||||||
|
username: credentials.username,
|
||||||
|
email: credentials.email,
|
||||||
|
token: resp.access_token,
|
||||||
|
refreshToken: resp.refresh_token,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
localStorage.setItem('redux-storage', JSON.stringify(state));
|
if (updateState) {
|
||||||
|
const state = createState(accountsData);
|
||||||
|
|
||||||
return { accounts: accountsData };
|
localStorage.setItem('redux-storage', JSON.stringify(state));
|
||||||
});
|
}
|
||||||
|
|
||||||
|
return { accounts: accountsData };
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Cypress.Commands.add('getByTestId', (id, options) =>
|
Cypress.Commands.add('getByTestId', (id, options) =>
|
||||||
cy.get(`[data-testid=${id}]`, options),
|
cy.get(`[data-testid=${id}]`, options),
|
||||||
|
13
tests-e2e/cypress/support/index.d.ts
vendored
13
tests-e2e/cypress/support/index.d.ts
vendored
@ -15,10 +15,21 @@ declare namespace Cypress {
|
|||||||
/**
|
/**
|
||||||
* Custom command to log in the user
|
* Custom command to log in the user
|
||||||
*
|
*
|
||||||
* @example cy.login(account)
|
* @example cy.login({ accounts: ['default'] })
|
||||||
*/
|
*/
|
||||||
login(options: {
|
login(options: {
|
||||||
accounts: AccountAlias[];
|
accounts: AccountAlias[];
|
||||||
|
/**
|
||||||
|
* defaults to `true`. if `false` — than only api response will
|
||||||
|
* be returned without mutating app state
|
||||||
|
* (useful for custom scenarios such as mocking of other api responses
|
||||||
|
* or checking whether account is registered)
|
||||||
|
*/
|
||||||
|
updateState?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether return raw api response without any conversion. Defaults to: `false`
|
||||||
|
*/
|
||||||
|
rawApiResp?: boolean;
|
||||||
}): Promise<{ accounts: Account[] }>;
|
}): Promise<{ accounts: Account[] }>;
|
||||||
|
|
||||||
getByTestId<S = any>(
|
getByTestId<S = any>(
|
||||||
|
Loading…
Reference in New Issue
Block a user