mirror of
				https://github.com/elyby/accounts-frontend.git
				synced 2025-05-31 14:11:58 +05:30 
			
		
		
		
	Fix the rest of the tests
This commit is contained in:
		| @@ -71,7 +71,12 @@ class RootPage extends React.PureComponent<{ | |||||||
|         > |         > | ||||||
|           <div className={styles.header} data-testid="toolbar"> |           <div className={styles.header} data-testid="toolbar"> | ||||||
|             <div className={styles.headerContent}> |             <div className={styles.headerContent}> | ||||||
|               <Link to="/" className={styles.logo} onClick={onLogoClick}> |               <Link | ||||||
|  |                 to="/" | ||||||
|  |                 className={styles.logo} | ||||||
|  |                 onClick={onLogoClick} | ||||||
|  |                 data-testid="home-page" | ||||||
|  |               > | ||||||
|                 <Message {...messages.siteName} /> |                 <Message {...messages.siteName} /> | ||||||
|               </Link> |               </Link> | ||||||
|               <div className={styles.userbar}> |               <div className={styles.userbar}> | ||||||
|   | |||||||
| @@ -68,7 +68,7 @@ describe('AuthFlow.functional', () => { | |||||||
|     it('should redirect guest / -> /login', () => { |     it('should redirect guest / -> /login', () => { | ||||||
|       navigate('/'); |       navigate('/'); | ||||||
|  |  | ||||||
|       expect(flow.navigate, 'was called once'); |       expect(flow.navigate, 'was called twice'); | ||||||
|       expect(flow.navigate, 'to have a call satisfying', ['/login']); |       expect(flow.navigate, 'to have a call satisfying', ['/login']); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
| @@ -80,8 +80,12 @@ describe('AuthFlow.functional', () => { | |||||||
|       navigate('/login'); |       navigate('/login'); | ||||||
|       navigate('/'); |       navigate('/'); | ||||||
|  |  | ||||||
|       expect(flow.navigate, 'was called twice'); |       expect(flow.navigate, 'was called thrice'); | ||||||
|       expect(flow.navigate, 'to have a call satisfying', ['/login']); |       expect(flow.navigate, 'to have calls satisfying', [ | ||||||
|  |         ['/login'], | ||||||
|  |         ['/login'], | ||||||
|  |         ['/login'], | ||||||
|  |       ]); | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -115,12 +115,6 @@ export default class AuthFlow implements AuthContext { | |||||||
|           options.replace = true; |           options.replace = true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.currentRequest = { |  | ||||||
|           path: route, |  | ||||||
|           params: {}, |  | ||||||
|           query: new URLSearchParams(), |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         if (this.replace) { |         if (this.replace) { | ||||||
|           this.replace(route); |           this.replace(route); | ||||||
|         } |         } | ||||||
| @@ -288,18 +282,18 @@ export default class AuthFlow implements AuthContext { | |||||||
|    * |    * | ||||||
|    * @returns {bool} - whether oauth state is being restored |    * @returns {bool} - whether oauth state is being restored | ||||||
|    */ |    */ | ||||||
|   private restoreOAuthState() { |   private restoreOAuthState(): boolean { | ||||||
|     if (/^\/(register|oauth2)/.test(this.getRequest().path)) { |  | ||||||
|       // allow register or the new oauth requests |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (this.oAuthStateRestored) { |     if (this.oAuthStateRestored) { | ||||||
|       return; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     this.oAuthStateRestored = true; |     this.oAuthStateRestored = true; | ||||||
|  |  | ||||||
|  |     if (/^\/(register|oauth2)/.test(this.getRequest().path)) { | ||||||
|  |       // allow register or the new oauth requests | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     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 | ||||||
|   | |||||||
| @@ -105,7 +105,7 @@ export default class CompleteState extends AbstractState { | |||||||
|         (resp: { redirectUri: string }) => { |         (resp: { redirectUri: string }) => { | ||||||
|           // TODO: пусть в стейт попадает флаг или тип авторизации |           // TODO: пусть в стейт попадает флаг или тип авторизации | ||||||
|           // вместо волшебства над редирект урлой |           // вместо волшебства над редирект урлой | ||||||
|           if (resp.redirectUri.indexOf('static_page') === 0) { |           if (resp.redirectUri.includes('static_page')) { | ||||||
|             context.setState(new FinishState()); |             context.setState(new FinishState()); | ||||||
|           } else { |           } else { | ||||||
|             return context.run('redirect', resp.redirectUri); |             return context.run('redirect', resp.redirectUri); | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ export default class LoginState extends AbstractState { | |||||||
|     const { user } = context.getState(); |     const { user } = context.getState(); | ||||||
|  |  | ||||||
|     const isUserAddsSecondAccount = |     const isUserAddsSecondAccount = | ||||||
|       !user.isGuest && /login|password/.test(context.getRequest().path); // TODO: improve me |       !user.isGuest && /login|password/.test(location.pathname); // TODO: improve me | ||||||
|  |  | ||||||
|     // TODO: it may not allow user to leave password state till he click back or enters password |     // TODO: it may not allow user to leave password state till he click back or enters password | ||||||
|     if (login) { |     if (login) { | ||||||
|   | |||||||
| @@ -15,9 +15,11 @@ import { AuthContext } from './AuthFlow'; | |||||||
|  |  | ||||||
| export default class PasswordState extends AbstractState { | export default class PasswordState extends AbstractState { | ||||||
|   enter(context: AuthContext) { |   enter(context: AuthContext) { | ||||||
|     const { login } = getCredentials(context.getState()); |     const { login, isTotpRequired } = getCredentials(context.getState()); | ||||||
|  |  | ||||||
|     if (login) { |     if (isTotpRequired) { | ||||||
|  |       context.setState(new MfaState()); | ||||||
|  |     } else if (login) { | ||||||
|       context.navigate('/password'); |       context.navigate('/password'); | ||||||
|     } else { |     } else { | ||||||
|       context.setState(new CompleteState()); |       context.setState(new CompleteState()); | ||||||
|   | |||||||
| @@ -9,19 +9,14 @@ singleAccount.accounts.available = singleAccount.accounts.available.filter( | |||||||
|   account => account.id === singleAccount.accounts.active, |   account => account.id === singleAccount.accounts.active, | ||||||
| ); | ); | ||||||
|  |  | ||||||
| describe("when user's token and refreshToken are invalid", () => { | describe('User with invalid token and refreshToken', () => { | ||||||
|   before(() => |   before(() => { | ||||||
|     // ensure we always have one account with correct token |     // ensure we always have one account with correct token | ||||||
|     cy.visit('/').then(() => |     cy.login({ | ||||||
|       fetch('/api/authentication/login', { |       accounts: ['default'], | ||||||
|         method: 'POST', |       updateState: false, | ||||||
|         headers: { |       rawApiResp: true, | ||||||
|           'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', |     }).then(({ accounts: [resp] }) => { | ||||||
|         }, |  | ||||||
|         body: `login=${account1.login}&password=${account1.password}`, |  | ||||||
|       }) |  | ||||||
|         .then(resp => resp.json()) |  | ||||||
|         .then(resp => { |  | ||||||
|       const account = multiAccount.accounts.available.find( |       const account = multiAccount.accounts.available.find( | ||||||
|         item => item.username === account1.username, |         item => item.username === account1.username, | ||||||
|       ); |       ); | ||||||
| @@ -31,9 +26,8 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|       } |       } | ||||||
|  |  | ||||||
|       account.token = resp.access_token; |       account.token = resp.access_token; | ||||||
|         }), |     }); | ||||||
|     ), |   }); | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   beforeEach(() => |   beforeEach(() => | ||||||
|     localStorage.setItem('redux-storage', JSON.stringify(multiAccount)), |     localStorage.setItem('redux-storage', JSON.stringify(multiAccount)), | ||||||
| @@ -46,7 +40,7 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|  |  | ||||||
|     cy.get('[name="password"]').type(`${account2.password}{enter}`); |     cy.get('[name="password"]').type(`${account2.password}{enter}`); | ||||||
|  |  | ||||||
|     cy.location('pathname', { timeout: 15000 }).should('eq', '/'); |     cy.location('pathname').should('eq', '/'); | ||||||
|     cy.contains('account preferences'); |     cy.contains('account preferences'); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
| @@ -60,18 +54,15 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|       .contains('Ely.by') |       .contains('Ely.by') | ||||||
|       .click(); |       .click(); | ||||||
|  |  | ||||||
|     // TODO: currently we can not skip redirect to /, but we will in future |     cy.url().should('include', '/password'); | ||||||
|     cy.location('pathname', { timeout: 15000 }).should('eq', '/'); |  | ||||||
|     cy.url({ timeout: 15000 }).should('include', '/password'); |  | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   it('should allow select account', () => { |   it('should allow select account', () => { | ||||||
|     // TODO: need a way to get valid token for one of the accounts |  | ||||||
|     cy.visit('/'); |     cy.visit('/'); | ||||||
|  |  | ||||||
|     cy.get('[data-e2e-go-back]').click(); |     cy.get('[data-e2e-go-back]').click(); | ||||||
|  |  | ||||||
|     cy.url().should('include', '/choose-account'); |     cy.location('pathname').should('eq', '/choose-account'); | ||||||
|  |  | ||||||
|     cy.get('[data-e2e-content]') |     cy.get('[data-e2e-content]') | ||||||
|       .contains(account2.email) |       .contains(account2.email) | ||||||
| @@ -80,8 +71,9 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|     cy.get('[data-e2e-content]') |     cy.get('[data-e2e-content]') | ||||||
|       .contains(account1.username) |       .contains(account1.username) | ||||||
|       .click(); |       .click(); | ||||||
|  |     cy.get('[name="password"]').type(`${account2.password}{enter}`); | ||||||
|  |  | ||||||
|     cy.location('pathname', { timeout: 15000 }).should('eq', '/'); |     cy.location('pathname').should('eq', '/'); | ||||||
|     cy.contains('account preferences'); |     cy.contains('account preferences'); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
| @@ -101,12 +93,20 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   it('should allow logout', () => { |   it('should allow logout', () => { | ||||||
|  |     cy.server(); | ||||||
|  |     cy.route({ | ||||||
|  |       url: `/api/v1/accounts/${account2.id}`, | ||||||
|  |     }).as('account'); | ||||||
|  |     cy.route({ | ||||||
|  |       method: 'POST', | ||||||
|  |       url: '/api/authentication/logout', | ||||||
|  |     }).as('logout'); | ||||||
|  |  | ||||||
|     cy.visit('/'); |     cy.visit('/'); | ||||||
|  |  | ||||||
|     cy.get('@fetch', { timeout: 15000 }).should( |     cy.wait('@account') | ||||||
|       'be.calledWith', |       .its('status') | ||||||
|       `/api/v1/accounts/${account2.id}`, |       .should('eq', 401); | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     cy.getByTestId('toolbar') |     cy.getByTestId('toolbar') | ||||||
|       .contains(account2.username) |       .contains(account2.username) | ||||||
| @@ -115,10 +115,7 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|       .contains('Log out') |       .contains('Log out') | ||||||
|       .click(); |       .click(); | ||||||
|  |  | ||||||
|     cy.get('@fetch', { timeout: 15000 }).should( |     cy.wait('@logout'); | ||||||
|       'be.calledWith', |  | ||||||
|       '/api/authentication/logout', |  | ||||||
|     ); |  | ||||||
|     cy.getByTestId('toolbar') |     cy.getByTestId('toolbar') | ||||||
|       .contains(account2.email) |       .contains(account2.email) | ||||||
|       .should('not.exist'); |       .should('not.exist'); | ||||||
| @@ -128,12 +125,16 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   it('should allow enter new login from choose account', () => { |   it('should allow enter new login from choose account', () => { | ||||||
|  |     cy.server(); | ||||||
|  |     cy.route({ | ||||||
|  |       url: `/api/v1/accounts/${account2.id}`, | ||||||
|  |     }).as('account'); | ||||||
|  |  | ||||||
|     cy.visit('/'); |     cy.visit('/'); | ||||||
|  |  | ||||||
|     cy.get('@fetch', { timeout: 15000 }).should( |     cy.wait('@account') | ||||||
|       'be.calledWith', |       .its('status') | ||||||
|       `/api/v1/accounts/${account2.id}`, |       .should('eq', 401); | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     cy.url().should('include', '/password'); |     cy.url().should('include', '/password'); | ||||||
|  |  | ||||||
| @@ -152,9 +153,10 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|  |  | ||||||
|     cy.get('[name=password]').type(account1.password); |     cy.get('[name=password]').type(account1.password); | ||||||
|     cy.get('[name=rememberMe]').should('be.checked'); |     cy.get('[name=rememberMe]').should('be.checked'); | ||||||
|  |     cy.get('[type=submit]').should('have.length', 1); // wait till transition ends | ||||||
|     cy.get('[type=submit]').click(); |     cy.get('[type=submit]').click(); | ||||||
|  |  | ||||||
|     cy.location('pathname', { timeout: 15000 }).should('eq', '/'); |     cy.location('pathname').should('eq', '/'); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   it('should allow logout from all accounts while choosing an account', () => { |   it('should allow logout from all accounts while choosing an account', () => { | ||||||
| @@ -195,7 +197,7 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|     cy.wait(1000); |     cy.wait(1000); | ||||||
|     cy.get('[name="password"]').type(`${account1.password}{enter}`); |     cy.get('[name="password"]').type(`${account1.password}{enter}`); | ||||||
|  |  | ||||||
|     cy.location('pathname', { timeout: 15000 }).should('eq', '/'); |     cy.location('pathname').should('eq', '/'); | ||||||
|     cy.contains('account preferences'); |     cy.contains('account preferences'); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
| @@ -254,7 +256,7 @@ describe("when user's token and refreshToken are invalid", () => { | |||||||
|  |  | ||||||
|     cy.get('[name=password]').type(`${account2.password}{enter}`); |     cy.get('[name=password]').type(`${account2.password}{enter}`); | ||||||
|  |  | ||||||
|     cy.url({ timeout: 15000 }).should('contain', '/oauth/choose-account'); |     cy.url().should('contain', '/oauth/choose-account'); | ||||||
|  |  | ||||||
|     cy.get('[data-e2e-content]') |     cy.get('[data-e2e-content]') | ||||||
|       .contains(account2.username) |       .contains(account2.username) | ||||||
|   | |||||||
| @@ -161,8 +161,8 @@ describe('OAuth', () => { | |||||||
|               ...defaults, |               ...defaults, | ||||||
|               // suggest preferred username |               // suggest preferred username | ||||||
|               // https://docs.ely.by/ru/oauth.html#id3 |               // https://docs.ely.by/ru/oauth.html#id3 | ||||||
|               login_hint: account.id, |               login_hint: String(account.id), | ||||||
|             })}`, |             }).toString()}`, | ||||||
|           ); |           ); | ||||||
|  |  | ||||||
|           cy.url().should('equal', 'https://ely.by/'); |           cy.url().should('equal', 'https://ely.by/'); | ||||||
| @@ -368,6 +368,12 @@ describe('OAuth', () => { | |||||||
|  |  | ||||||
|   describe('static pages', () => { |   describe('static pages', () => { | ||||||
|     it('should authenticate using static page', () => { |     it('should authenticate using static page', () => { | ||||||
|  |       cy.server(); | ||||||
|  |       cy.route({ | ||||||
|  |         method: 'POST', | ||||||
|  |         url: '/api/oauth2/v1/complete**', | ||||||
|  |       }).as('complete'); | ||||||
|  |  | ||||||
|       cy.login({ accounts: ['default'] }); |       cy.login({ accounts: ['default'] }); | ||||||
|  |  | ||||||
|       cy.visit( |       cy.visit( | ||||||
| @@ -378,10 +384,18 @@ describe('OAuth', () => { | |||||||
|         })}`, |         })}`, | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|  |       cy.wait('@complete'); | ||||||
|  |  | ||||||
|       cy.url().should('include', 'oauth/finish#{%22auth_code%22:'); |       cy.url().should('include', 'oauth/finish#{%22auth_code%22:'); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it('should authenticate using static page with code', () => { |     it('should authenticate using static page with code', () => { | ||||||
|  |       cy.server(); | ||||||
|  |       cy.route({ | ||||||
|  |         method: 'POST', | ||||||
|  |         url: '/api/oauth2/v1/complete**', | ||||||
|  |       }).as('complete'); | ||||||
|  |  | ||||||
|       cy.login({ accounts: ['default'] }); |       cy.login({ accounts: ['default'] }); | ||||||
|  |  | ||||||
|       cy.visit( |       cy.visit( | ||||||
| @@ -392,6 +406,8 @@ describe('OAuth', () => { | |||||||
|         })}`, |         })}`, | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|  |       cy.wait('@complete'); | ||||||
|  |  | ||||||
|       cy.url().should('include', 'oauth/finish#{%22auth_code%22:'); |       cy.url().should('include', 'oauth/finish#{%22auth_code%22:'); | ||||||
|  |  | ||||||
|       cy.getByTestId('oauth-code-container').should( |       cy.getByTestId('oauth-code-container').should( | ||||||
| @@ -404,15 +420,12 @@ describe('OAuth', () => { | |||||||
|       // https://github.com/cypress-io/cypress/issues/2752 |       // https://github.com/cypress-io/cypress/issues/2752 | ||||||
|       cy.getByTestId('oauth-code-container') |       cy.getByTestId('oauth-code-container') | ||||||
|         .contains('Copy') |         .contains('Copy') | ||||||
|         .click({ |         .click(); | ||||||
|           // TODO: forcing, because currently we have needless re-renders, that causing |  | ||||||
|           // button to disappear for some time and to be unclickable |  | ||||||
|           force: true, |  | ||||||
|         }); |  | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  | }); | ||||||
|  |  | ||||||
|   function assertPermissions() { | function assertPermissions() { | ||||||
|   cy.url().should('include', '/oauth/permissions'); |   cy.url().should('include', '/oauth/permissions'); | ||||||
|  |  | ||||||
|   cy.getByTestId('auth-header').should('contain', 'Application permissions'); |   cy.getByTestId('auth-header').should('contain', 'Application permissions'); | ||||||
| @@ -424,5 +437,4 @@ describe('OAuth', () => { | |||||||
|     'contain', |     'contain', | ||||||
|     'Access to your E‑mail address', |     'Access to your E‑mail address', | ||||||
|   ); |   ); | ||||||
|   } | } | ||||||
| }); |  | ||||||
|   | |||||||
| @@ -46,6 +46,16 @@ describe('Sign in / Log out', () => { | |||||||
|       }); |       }); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |   it('should force to /login page', () => { | ||||||
|  |     cy.visit('/'); | ||||||
|  |  | ||||||
|  |     cy.location('pathname').should('eq', '/login'); | ||||||
|  |  | ||||||
|  |     cy.getByTestId('home-page').click(); | ||||||
|  |  | ||||||
|  |     cy.location('pathname').should('eq', '/login'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   it('should sign in without remember me', () => { |   it('should sign in without remember me', () => { | ||||||
|     cy.visit('/'); |     cy.visit('/'); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								tests-e2e/cypress/support/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								tests-e2e/cypress/support/index.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -30,8 +30,20 @@ declare namespace Cypress { | |||||||
|       /** |       /** | ||||||
|        * Whether return raw api response without any conversion. Defaults to: `false` |        * Whether return raw api response without any conversion. Defaults to: `false` | ||||||
|        */ |        */ | ||||||
|       rawApiResp?: boolean; |       rawApiResp?: false; | ||||||
|     }): Promise<{ accounts: TAccount[] }>; |     }): Promise<{ accounts: TAccount[] }>; | ||||||
|  |     login(options: { | ||||||
|  |       accounts: AccountAlias[]; | ||||||
|  |       updateState?: boolean; | ||||||
|  |       rawApiResp: true; | ||||||
|  |     }): Promise<{ | ||||||
|  |       accounts: { | ||||||
|  |         success: true; | ||||||
|  |         access_token: string; | ||||||
|  |         expires_in: number; | ||||||
|  |         refresh_token: string; | ||||||
|  |       }[]; | ||||||
|  |     }>; | ||||||
|  |  | ||||||
|     getByTestId<S = any>( |     getByTestId<S = any>( | ||||||
|       id: string, |       id: string, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user