mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-11-09 01:22:27 +05:30
Add more auth/oauth/multi-acc related test cases
This commit is contained in:
parent
0325f0aac4
commit
951f538ee5
@ -66,9 +66,10 @@ export class AccountSwitcher extends React.Component<Props> {
|
|||||||
styles.accountSwitcher,
|
styles.accountSwitcher,
|
||||||
styles[`${skin}AccountSwitcher`],
|
styles[`${skin}AccountSwitcher`],
|
||||||
)}
|
)}
|
||||||
|
data-testid="account-switcher"
|
||||||
>
|
>
|
||||||
{highlightActiveAccount ? (
|
{highlightActiveAccount && (
|
||||||
<div className={styles.item}>
|
<div className={styles.item} data-testid="active-account">
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
styles.accountIcon,
|
styles.accountIcon,
|
||||||
@ -97,6 +98,7 @@ export class AccountSwitcher extends React.Component<Props> {
|
|||||||
<div className={styles.link}>
|
<div className={styles.link}>
|
||||||
<a
|
<a
|
||||||
className={styles.link}
|
className={styles.link}
|
||||||
|
data-testid="logout-account"
|
||||||
onClick={this.onRemove(activeAccount)}
|
onClick={this.onRemove(activeAccount)}
|
||||||
href="#"
|
href="#"
|
||||||
>
|
>
|
||||||
@ -106,11 +108,13 @@ export class AccountSwitcher extends React.Component<Props> {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
)}
|
||||||
|
|
||||||
{available.map((account, index) => (
|
{available.map((account, index) => (
|
||||||
<div
|
<div
|
||||||
className={clsx(styles.item, styles.accountSwitchItem)}
|
className={clsx(styles.item, styles.accountSwitchItem)}
|
||||||
key={account.id}
|
key={account.id}
|
||||||
|
data-e2e-account-id={account.id}
|
||||||
onClick={this.onSwitch(account)}
|
onClick={this.onSwitch(account)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -125,6 +129,7 @@ export class AccountSwitcher extends React.Component<Props> {
|
|||||||
{allowLogout ? (
|
{allowLogout ? (
|
||||||
<div
|
<div
|
||||||
className={styles.logoutIcon}
|
className={styles.logoutIcon}
|
||||||
|
data-testid="logout-account"
|
||||||
onClick={this.onRemove(account)}
|
onClick={this.onRemove(account)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@ -141,6 +146,7 @@ export class AccountSwitcher extends React.Component<Props> {
|
|||||||
<Link to="/login" onClick={this.props.onAfterAction}>
|
<Link to="/login" onClick={this.props.onAfterAction}>
|
||||||
<Button
|
<Button
|
||||||
color={COLOR_WHITE}
|
color={COLOR_WHITE}
|
||||||
|
data-testid="add-account"
|
||||||
block
|
block
|
||||||
small
|
small
|
||||||
className={styles.addAccount}
|
className={styles.addAccount}
|
||||||
|
@ -89,10 +89,12 @@ class RootPage extends React.PureComponent<{
|
|||||||
<Route path="/rules" component={RulesPage} />
|
<Route path="/rules" component={RulesPage} />
|
||||||
<Route path="/dev" component={DevPage} />
|
<Route path="/dev" component={DevPage} />
|
||||||
|
|
||||||
{!user.isGuest && (
|
<AuthFlowRoute
|
||||||
<PrivateRoute exact path="/" component={ProfilePage} />
|
exact
|
||||||
)}
|
path="/"
|
||||||
|
key="indexPage"
|
||||||
|
component={user.isGuest ? AuthPage : ProfilePage}
|
||||||
|
/>
|
||||||
<AuthFlowRoute path="/" component={AuthPage} />
|
<AuthFlowRoute path="/" component={AuthPage} />
|
||||||
|
|
||||||
<Route component={PageNotFound} />
|
<Route component={PageNotFound} />
|
||||||
|
@ -77,6 +77,7 @@ export default class AuthFlow implements AuthContext {
|
|||||||
onReady: () => void;
|
onReady: () => void;
|
||||||
navigate: (route: string, options: { replace?: boolean }) => void;
|
navigate: (route: string, options: { replace?: boolean }) => void;
|
||||||
currentRequest: Request;
|
currentRequest: Request;
|
||||||
|
oAuthStateRestored = false;
|
||||||
dispatch: (action: { [key: string]: any }) => void;
|
dispatch: (action: { [key: string]: any }) => void;
|
||||||
getState: () => RootState;
|
getState: () => RootState;
|
||||||
|
|
||||||
@ -184,9 +185,6 @@ export default class AuthFlow implements AuthContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {object} - current request object
|
|
||||||
*/
|
|
||||||
getRequest() {
|
getRequest() {
|
||||||
return {
|
return {
|
||||||
path: '',
|
path: '',
|
||||||
@ -296,6 +294,12 @@ export default class AuthFlow implements AuthContext {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.oAuthStateRestored) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oAuthStateRestored = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(localStorage.getItem('oauthData'));
|
const data = JSON.parse(localStorage.getItem('oauthData'));
|
||||||
const expirationTime = 2 * 60 * 60 * 1000; // 2h
|
const expirationTime = 2 * 60 * 60 * 1000; // 2h
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"account1": {
|
"account1": {
|
||||||
"id": "7",
|
"id": 7,
|
||||||
"username": "SleepWalker",
|
"username": "SleepWalker",
|
||||||
"email": "danilenkos@auroraglobal.com",
|
"email": "danilenkos@auroraglobal.com",
|
||||||
"login": "SleepWalker",
|
"login": "SleepWalker",
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
|
import { account1 } from '../../fixtures/accounts.json';
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
client_id: 'ely',
|
client_id: 'ely',
|
||||||
redirect_uri: 'http://ely.by/authorization/oauth',
|
redirect_uri: 'http://ely.by/authorization/oauth',
|
||||||
@ -14,6 +16,29 @@ it('should complete oauth', () => {
|
|||||||
cy.url().should('equal', 'https://ely.by/');
|
cy.url().should('equal', 'https://ely.by/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should restore previous oauthData if any', () => {
|
||||||
|
localStorage.setItem(
|
||||||
|
'oauthData',
|
||||||
|
JSON.stringify({
|
||||||
|
timestamp: Date.now() - 3600,
|
||||||
|
payload: {
|
||||||
|
clientId: 'ely',
|
||||||
|
redirectUrl: 'http://ely.by/authorization/oauth',
|
||||||
|
responseType: 'code',
|
||||||
|
description: null,
|
||||||
|
scope: 'account_info account_email',
|
||||||
|
loginHint: null,
|
||||||
|
state: null,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
cy.login({ accounts: ['default'] });
|
||||||
|
|
||||||
|
cy.visit('/');
|
||||||
|
|
||||||
|
cy.url().should('equal', 'https://ely.by/');
|
||||||
|
});
|
||||||
|
|
||||||
it('should ask to choose an account if user has multiple', () => {
|
it('should ask to choose an account if user has multiple', () => {
|
||||||
cy.login({ accounts: ['default', 'default2'] }).then(
|
cy.login({ accounts: ['default', 'default2'] }).then(
|
||||||
({ accounts: [account] }) => {
|
({ accounts: [account] }) => {
|
||||||
@ -72,6 +97,20 @@ it('should prompt for permissions', () => {
|
|||||||
cy.url().should('match', /^http:\/\/localhost:8080\/?\?code=[^&]+&state=$/);
|
cy.url().should('match', /^http:\/\/localhost:8080\/?\?code=[^&]+&state=$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow sign in during oauth (guest oauth)', () => {
|
||||||
|
cy.visit(`/oauth2/v1/ely?${new URLSearchParams(defaults)}`);
|
||||||
|
|
||||||
|
cy.url().should('include', '/login');
|
||||||
|
|
||||||
|
cy.get('[name=login]').type(`${account1.login}{enter}`);
|
||||||
|
|
||||||
|
cy.url().should('include', '/password');
|
||||||
|
|
||||||
|
cy.get('[name=password]').type(`${account1.password}{enter}`);
|
||||||
|
|
||||||
|
cy.url().should('equal', 'https://ely.by/');
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: enable, when backend api will return correct response on auth decline
|
// TODO: enable, when backend api will return correct response on auth decline
|
||||||
xit('should redirect to error page, when permission request declined', () => {
|
xit('should redirect to error page, when permission request declined', () => {
|
||||||
cy.server();
|
cy.server();
|
||||||
@ -170,7 +209,28 @@ describe('login_hint', () => {
|
|||||||
|
|
||||||
describe('prompts', () => {
|
describe('prompts', () => {
|
||||||
it('should prompt for account', () => {
|
it('should prompt for account', () => {
|
||||||
cy.login({ accounts: ['default'] });
|
cy.login({ accounts: ['default'] }).then(({ accounts: [account] }) => {
|
||||||
|
cy.visit(
|
||||||
|
`/oauth2/v1/ely?${new URLSearchParams({
|
||||||
|
...defaults,
|
||||||
|
prompt: 'select_account',
|
||||||
|
})}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.url().should('include', '/oauth/choose-account');
|
||||||
|
|
||||||
|
cy.getByTestId('auth-header').should('contain', 'Choose an account');
|
||||||
|
|
||||||
|
cy.getByTestId('auth-body')
|
||||||
|
.contains(account.email)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.url().should('equal', 'https://ely.by/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow sign in with another account', () => {
|
||||||
|
cy.login({ accounts: ['default2'] });
|
||||||
|
|
||||||
cy.visit(
|
cy.visit(
|
||||||
`/oauth2/v1/ely?${new URLSearchParams({
|
`/oauth2/v1/ely?${new URLSearchParams({
|
||||||
@ -181,7 +241,19 @@ describe('prompts', () => {
|
|||||||
|
|
||||||
cy.url().should('include', '/oauth/choose-account');
|
cy.url().should('include', '/oauth/choose-account');
|
||||||
|
|
||||||
cy.getByTestId('auth-header').should('contain', 'Choose an account');
|
cy.getByTestId('auth-controls')
|
||||||
|
.contains('another account')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.url().should('include', '/login');
|
||||||
|
|
||||||
|
cy.get('[name=login]').type(`${account1.login}{enter}`);
|
||||||
|
|
||||||
|
cy.url().should('include', '/password');
|
||||||
|
|
||||||
|
cy.get('[name=password]').type(`${account1.password}{enter}`);
|
||||||
|
|
||||||
|
cy.url().should('equal', 'https://ely.by/');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prompt for permissions', () => {
|
it('should prompt for permissions', () => {
|
||||||
@ -258,6 +330,33 @@ describe('prompts', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow sign in during oauth (guest oauth)', () => {
|
||||||
|
cy.visit(
|
||||||
|
`/oauth2/v1/ely?${new URLSearchParams({
|
||||||
|
...defaults,
|
||||||
|
client_id: 'tlauncher',
|
||||||
|
redirect_uri: 'http://localhost:8080',
|
||||||
|
prompt: 'select_account,consent',
|
||||||
|
})}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.url().should('include', '/login');
|
||||||
|
|
||||||
|
cy.get('[name=login]').type(`${account1.login}{enter}`);
|
||||||
|
|
||||||
|
cy.url().should('include', '/password');
|
||||||
|
|
||||||
|
cy.get('[name=password]').type(`${account1.password}{enter}`);
|
||||||
|
|
||||||
|
assertPermissions();
|
||||||
|
|
||||||
|
cy.getByTestId('auth-controls')
|
||||||
|
.contains('Approve')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.url().should('match', /^http:\/\/localhost:8080\/?\?code=[^&]+&state=$/);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('static pages', () => {
|
describe('static pages', () => {
|
@ -1,8 +1,10 @@
|
|||||||
import { account1 } from '../../fixtures/accounts.json';
|
import { account1, account2 } from '../../fixtures/accounts.json';
|
||||||
|
|
||||||
it('should sign in', () => {
|
it('should sign in', () => {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
|
|
||||||
|
cy.url().should('include', '/login');
|
||||||
|
|
||||||
cy.get('[name=login]').type(`${account1.login}{enter}`);
|
cy.get('[name=login]').type(`${account1.login}{enter}`);
|
||||||
|
|
||||||
cy.url().should('include', '/password');
|
cy.url().should('include', '/password');
|
||||||
@ -122,3 +124,129 @@ it('should sign in with totp', () => {
|
|||||||
|
|
||||||
cy.location('pathname').should('eq', '/');
|
cy.location('pathname').should('eq', '/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow logout', () => {
|
||||||
|
cy.login({ accounts: ['default'] });
|
||||||
|
|
||||||
|
cy.visit('/');
|
||||||
|
|
||||||
|
cy.getByTestId('toolbar')
|
||||||
|
.contains(account1.username)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.getByTestId('active-account')
|
||||||
|
.getByTestId('logout-account')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/login');
|
||||||
|
cy.getByTestId('toolbar').should('contain', 'Join');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('multi account', () => {
|
||||||
|
it('should allow sign in with another account', () => {
|
||||||
|
cy.login({ accounts: ['default2'] });
|
||||||
|
|
||||||
|
cy.visit('/');
|
||||||
|
|
||||||
|
cy.getByTestId('toolbar')
|
||||||
|
.contains(account2.username)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.getByTestId('active-account').should('have.length', 1);
|
||||||
|
cy.get('[data-e2e-account-id]').should('have.length', 0);
|
||||||
|
|
||||||
|
cy.getByTestId('add-account').click();
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/login');
|
||||||
|
|
||||||
|
cy.get('[data-e2e-go-back]').should('exist');
|
||||||
|
|
||||||
|
cy.get('[name=login]').type(`${account1.login}{enter}`);
|
||||||
|
|
||||||
|
cy.url().should('include', '/password');
|
||||||
|
|
||||||
|
cy.get('[name=password]').type(`${account1.password}{enter}`);
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/');
|
||||||
|
|
||||||
|
cy.getByTestId('toolbar')
|
||||||
|
.contains(account1.username)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.getByTestId('active-account').should('have.length', 1);
|
||||||
|
cy.get('[data-e2e-account-id]').should('have.length', 1);
|
||||||
|
|
||||||
|
cy.get('[data-e2e-account-id]')
|
||||||
|
.getByTestId('logout-account')
|
||||||
|
.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should go back to profile from login screen', () => {
|
||||||
|
cy.login({ accounts: ['default'] });
|
||||||
|
|
||||||
|
cy.visit('/');
|
||||||
|
|
||||||
|
cy.getByTestId('toolbar')
|
||||||
|
.contains(account1.username)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.getByTestId('add-account').click();
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/login');
|
||||||
|
|
||||||
|
cy.get('[data-e2e-go-back]').click();
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow logout active account', () => {
|
||||||
|
cy.login({ accounts: ['default', 'default2'] });
|
||||||
|
|
||||||
|
cy.visit('/');
|
||||||
|
|
||||||
|
cy.getByTestId('toolbar')
|
||||||
|
.contains(account1.username)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.getByTestId('active-account')
|
||||||
|
.getByTestId('logout-account')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.getByTestId('toolbar')
|
||||||
|
.contains(account2.username)
|
||||||
|
.click();
|
||||||
|
cy.get('[data-e2e-account-id]').should('have.length', 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow log in the same account twice', () => {
|
||||||
|
cy.login({ accounts: ['default'] });
|
||||||
|
|
||||||
|
cy.visit('/');
|
||||||
|
|
||||||
|
cy.getByTestId('toolbar')
|
||||||
|
.contains(account1.username)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.getByTestId('active-account').should('have.length', 1);
|
||||||
|
cy.get('[data-e2e-account-id]').should('have.length', 0);
|
||||||
|
|
||||||
|
cy.getByTestId('add-account').click();
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/login');
|
||||||
|
|
||||||
|
cy.get('[data-e2e-go-back]').should('exist');
|
||||||
|
|
||||||
|
cy.get('[name=login]').type(`${account1.login}{enter}`);
|
||||||
|
|
||||||
|
cy.url().should('include', '/password');
|
||||||
|
|
||||||
|
cy.get('[name=password]').type(`${account1.password}{enter}`);
|
||||||
|
|
||||||
|
cy.location('pathname').should('eq', '/');
|
||||||
|
|
||||||
|
cy.getByTestId('toolbar')
|
||||||
|
.contains(account1.username)
|
||||||
|
.click();
|
||||||
|
cy.get('[data-e2e-account-id]').should('have.length', 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -27,8 +27,8 @@ import { account1, account2 } from '../fixtures/accounts';
|
|||||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||||
|
|
||||||
const accountsMap = {
|
const accountsMap = {
|
||||||
default: account2,
|
default: account1,
|
||||||
default2: account1,
|
default2: account2,
|
||||||
};
|
};
|
||||||
|
|
||||||
Cypress.Commands.add(
|
Cypress.Commands.add(
|
||||||
@ -82,8 +82,18 @@ Cypress.Commands.add(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Cypress.Commands.add('getByTestId', (id, options) =>
|
Cypress.Commands.add(
|
||||||
cy.get(`[data-testid=${id}]`, options),
|
'getByTestId',
|
||||||
|
{ prevSubject: 'optional' },
|
||||||
|
(subject, id, options) => {
|
||||||
|
const selector = `[data-testid=${id}]`;
|
||||||
|
|
||||||
|
if (subject) {
|
||||||
|
return cy.wrap(subject.find(selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cy.get(selector, options);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
function createState(accounts) {
|
function createState(accounts) {
|
||||||
|
Loading…
Reference in New Issue
Block a user