mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-11-30 10:42:34 +05:30
Add RequestAbortedError and fix current e2e tests
This commit is contained in:
parent
a9d67bc3e7
commit
71bfc01e4d
@ -8,14 +8,16 @@ const ABORT_ERR = 20;
|
|||||||
|
|
||||||
export default function BsodMiddleware(dispatchBsod: Function, logger: Logger) {
|
export default function BsodMiddleware(dispatchBsod: Function, logger: Logger) {
|
||||||
return {
|
return {
|
||||||
catch<T: Resp<*> | InternalServerError>(resp?: T): Promise<T> {
|
catch<T: Resp<*> | InternalServerError | Error>(resp?: T): Promise<T> {
|
||||||
if (resp && (
|
const originalResponse: Object = (resp && resp.originalResponse) || {};
|
||||||
(resp instanceof InternalServerError
|
|
||||||
&& resp.error.code !== ABORT_ERR
|
if (
|
||||||
) || (resp.originalResponse
|
resp
|
||||||
&& /5\d\d/.test((resp.originalResponse.status: string))
|
&& ((resp instanceof InternalServerError
|
||||||
)
|
&& resp.error.code !== ABORT_ERR)
|
||||||
)) {
|
|| (originalResponse
|
||||||
|
&& /5\d\d/.test((originalResponse.status: string))))
|
||||||
|
) {
|
||||||
dispatchBsod();
|
dispatchBsod();
|
||||||
|
|
||||||
if (!resp.message || !/NetworkError/.test(resp.message)) {
|
if (!resp.message || !/NetworkError/.test(resp.message)) {
|
||||||
@ -25,7 +27,7 @@ export default function BsodMiddleware(dispatchBsod: Function, logger: Logger) {
|
|||||||
message = `BSoD: ${resp.message}`;
|
message = `BSoD: ${resp.message}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.warn(message, {resp});
|
logger.warn(message, { resp });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
// @flow
|
// @flow
|
||||||
function InternalServerError(error: Error | string | Object, resp?: Response | Object) {
|
function InternalServerError(
|
||||||
|
error: Error | string | Object,
|
||||||
|
resp?: Response | Object
|
||||||
|
) {
|
||||||
error = error || {};
|
error = error || {};
|
||||||
|
|
||||||
this.name = 'InternalServerError';
|
this.name = 'InternalServerError';
|
||||||
this.message = 'InternalServerError';
|
this.message = 'InternalServerError';
|
||||||
this.error = error;
|
this.error = error;
|
||||||
this.stack = (new Error()).stack;
|
this.stack = new Error().stack;
|
||||||
|
|
||||||
if (resp) {
|
if (resp) {
|
||||||
this.originalResponse = resp;
|
this.originalResponse = resp;
|
||||||
|
23
src/services/request/RequestAbortedError.js
Normal file
23
src/services/request/RequestAbortedError.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// @flow
|
||||||
|
function RequestAbortedError(error: Error | Response) {
|
||||||
|
this.name = 'RequestAbortedError';
|
||||||
|
this.message = 'RequestAbortedError';
|
||||||
|
this.error = error;
|
||||||
|
this.stack = new Error().stack;
|
||||||
|
|
||||||
|
if (error.message) {
|
||||||
|
this.message = error.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof error === 'string') {
|
||||||
|
this.message = error;
|
||||||
|
} else {
|
||||||
|
this.error = error;
|
||||||
|
Object.assign(this, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestAbortedError.prototype = Object.create(Error.prototype);
|
||||||
|
RequestAbortedError.prototype.constructor = RequestAbortedError;
|
||||||
|
|
||||||
|
export default RequestAbortedError;
|
@ -2,6 +2,7 @@
|
|||||||
export { default } from './request';
|
export { default } from './request';
|
||||||
export type { Resp } from './request';
|
export type { Resp } from './request';
|
||||||
export { default as InternalServerError } from './InternalServerError';
|
export { default as InternalServerError } from './InternalServerError';
|
||||||
|
export { default as RequestAbortedError } from './RequestAbortedError';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Usage: Query<'requeired'|'keys'|'names'>
|
* Usage: Query<'requeired'|'keys'|'names'>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import PromiseMiddlewareLayer from './PromiseMiddlewareLayer';
|
import PromiseMiddlewareLayer from './PromiseMiddlewareLayer';
|
||||||
import InternalServerError from './InternalServerError';
|
import InternalServerError from './InternalServerError';
|
||||||
|
import RequestAbortedError from './RequestAbortedError';
|
||||||
|
|
||||||
const middlewareLayer = new PromiseMiddlewareLayer();
|
const middlewareLayer = new PromiseMiddlewareLayer();
|
||||||
|
|
||||||
@ -17,10 +18,10 @@ type Middleware = {
|
|||||||
const buildOptions = (method: string, data?: Object, options: Object) => ({
|
const buildOptions = (method: string, data?: Object, options: Object) => ({
|
||||||
method,
|
method,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||||
},
|
},
|
||||||
body: buildQuery(data),
|
body: buildQuery(data),
|
||||||
...options,
|
...options
|
||||||
});
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -31,7 +32,11 @@ export default {
|
|||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
post<T>(url: string, data?: Object, options: Object = {}): Promise<Resp<T>> {
|
post<T>(
|
||||||
|
url: string,
|
||||||
|
data?: Object,
|
||||||
|
options: Object = {}
|
||||||
|
): Promise<Resp<T>> {
|
||||||
return doFetch(url, buildOptions('POST', data, options));
|
return doFetch(url, buildOptions('POST', data, options));
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -55,7 +60,11 @@ export default {
|
|||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
delete<T>(url: string, data?: Object, options: Object = {}): Promise<Resp<T>> {
|
delete<T>(
|
||||||
|
url: string,
|
||||||
|
data?: Object,
|
||||||
|
options: Object = {}
|
||||||
|
): Promise<Resp<T>> {
|
||||||
return doFetch(url, buildOptions('DELETE', data, options));
|
return doFetch(url, buildOptions('DELETE', data, options));
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -93,34 +102,38 @@ export default {
|
|||||||
*/
|
*/
|
||||||
addMiddleware(middleware: Middleware) {
|
addMiddleware(middleware: Middleware) {
|
||||||
middlewareLayer.add(middleware);
|
middlewareLayer.add(middleware);
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkStatus = (resp: Response) => resp.status >= 200 && resp.status < 300
|
const checkStatus = (resp: Response) =>
|
||||||
|
resp.status >= 200 && resp.status < 300
|
||||||
? Promise.resolve(resp)
|
? Promise.resolve(resp)
|
||||||
: Promise.reject(resp);
|
: Promise.reject(resp);
|
||||||
const toJSON = (resp = {}) => {
|
const toJSON = (resp: Response) => {
|
||||||
if (!resp.json) {
|
if (!resp.json || resp.status === 0) {
|
||||||
// e.g. 'TypeError: Failed to fetch' due to CORS
|
// e.g. 'TypeError: Failed to fetch' due to CORS or request was aborted
|
||||||
throw new InternalServerError(resp);
|
throw new RequestAbortedError(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.json().then((json) => {
|
return resp.json().then(
|
||||||
|
(json) => {
|
||||||
json.originalResponse = resp;
|
json.originalResponse = resp;
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}, (error) => Promise.reject(
|
},
|
||||||
new InternalServerError(error, resp)
|
(error) => Promise.reject(new InternalServerError(error, resp))
|
||||||
));
|
);
|
||||||
};
|
};
|
||||||
const rejectWithJSON = (resp) => toJSON(resp).then((resp) => {
|
const rejectWithJSON = (resp: Response) =>
|
||||||
|
toJSON(resp).then((resp) => {
|
||||||
if (resp.originalResponse.status >= 500) {
|
if (resp.originalResponse.status >= 500) {
|
||||||
throw new InternalServerError(resp, resp.originalResponse);
|
throw new InternalServerError(resp, resp.originalResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw resp;
|
throw resp;
|
||||||
});
|
});
|
||||||
const handleResponseSuccess = (resp) => resp.success || typeof resp.success === 'undefined'
|
const handleResponseSuccess = (resp) =>
|
||||||
|
resp.success || typeof resp.success === 'undefined'
|
||||||
? Promise.resolve(resp)
|
? Promise.resolve(resp)
|
||||||
: Promise.reject(resp);
|
: Promise.reject(resp);
|
||||||
|
|
||||||
@ -131,14 +144,21 @@ async function doFetch(url, options = {}) {
|
|||||||
options.headers = options.headers || {};
|
options.headers = options.headers || {};
|
||||||
options.headers.Accept = 'application/json';
|
options.headers.Accept = 'application/json';
|
||||||
|
|
||||||
return middlewareLayer.run('before', {url, options})
|
return middlewareLayer
|
||||||
.then(({url, options}) =>
|
.run('before', { url, options })
|
||||||
|
.then(({ url, options }) =>
|
||||||
fetch(url, options)
|
fetch(url, options)
|
||||||
.then(checkStatus)
|
.then(checkStatus)
|
||||||
.then(toJSON, rejectWithJSON)
|
.then(toJSON, rejectWithJSON)
|
||||||
.then(handleResponseSuccess)
|
.then(handleResponseSuccess)
|
||||||
.then((resp) => middlewareLayer.run('then', resp, {url, options}))
|
.then((resp) =>
|
||||||
.catch((resp) => middlewareLayer.run('catch', resp, {url, options}, () => doFetch(url, options)))
|
middlewareLayer.run('then', resp, { url, options })
|
||||||
|
)
|
||||||
|
.catch((resp) =>
|
||||||
|
middlewareLayer.run('catch', resp, { url, options }, () =>
|
||||||
|
doFetch(url, options)
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,8 +194,7 @@ function convertQueryValue(value) {
|
|||||||
*/
|
*/
|
||||||
function buildQuery(data: Object = {}): string {
|
function buildQuery(data: Object = {}): string {
|
||||||
return Object.keys(data)
|
return Object.keys(data)
|
||||||
.map(
|
.map((keyName) =>
|
||||||
(keyName) =>
|
|
||||||
[keyName, convertQueryValue(data[keyName])]
|
[keyName, convertQueryValue(data[keyName])]
|
||||||
.map(encodeURIComponent)
|
.map(encodeURIComponent)
|
||||||
.join('=')
|
.join('=')
|
||||||
|
@ -2,7 +2,7 @@ import expect from 'unexpected';
|
|||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
|
|
||||||
import request from 'services/request';
|
import request from 'services/request';
|
||||||
import { InternalServerError } from 'services/request';
|
import { InternalServerError, RequestAbortedError } from 'services/request';
|
||||||
|
|
||||||
describe('services/request', () => {
|
describe('services/request', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -14,26 +14,12 @@ describe('services/request', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('InternalServerError', () => {
|
describe('InternalServerError', () => {
|
||||||
it('should wrap fetch error', () => {
|
|
||||||
const resp = new TypeError('Fetch error');
|
|
||||||
|
|
||||||
fetch.returns(Promise.reject(resp));
|
|
||||||
|
|
||||||
return expect(request.get('/foo'), 'to be rejected')
|
|
||||||
.then((error) => {
|
|
||||||
expect(error, 'to be an', InternalServerError);
|
|
||||||
expect(error.originalResponse, 'to be undefined');
|
|
||||||
expect(error.message, 'to equal', resp.message);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should wrap json errors', () => {
|
it('should wrap json errors', () => {
|
||||||
const resp = new Response('bad resp format', {status: 200});
|
const resp = new Response('bad resp format', { status: 200 });
|
||||||
|
|
||||||
fetch.returns(Promise.resolve(resp));
|
fetch.returns(Promise.resolve(resp));
|
||||||
|
|
||||||
return expect(request.get('/foo'), 'to be rejected')
|
return expect(request.get('/foo'), 'to be rejected').then((error) => {
|
||||||
.then((error) => {
|
|
||||||
expect(error, 'to be an', InternalServerError);
|
expect(error, 'to be an', InternalServerError);
|
||||||
expect(error.originalResponse, 'to be', resp);
|
expect(error.originalResponse, 'to be', resp);
|
||||||
expect(error.message, 'to contain', 'Unexpected token');
|
expect(error.message, 'to contain', 'Unexpected token');
|
||||||
@ -41,16 +27,38 @@ describe('services/request', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should wrap 5xx errors', () => {
|
it('should wrap 5xx errors', () => {
|
||||||
const resp = new Response('{}', {status: 500});
|
const resp = new Response('{}', { status: 500 });
|
||||||
|
|
||||||
fetch.returns(Promise.resolve(resp));
|
fetch.returns(Promise.resolve(resp));
|
||||||
|
|
||||||
return expect(request.get('/foo'), 'to be rejected')
|
return expect(request.get('/foo'), 'to be rejected').then((error) => {
|
||||||
.then((error) => {
|
|
||||||
expect(error, 'to be an', InternalServerError);
|
expect(error, 'to be an', InternalServerError);
|
||||||
expect(error.originalResponse, 'to be', resp);
|
expect(error.originalResponse, 'to be', resp);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should wrap aborted errors', () => {
|
||||||
|
const resp = new Response('{}', { status: 0 });
|
||||||
|
|
||||||
|
fetch.returns(Promise.resolve(resp));
|
||||||
|
|
||||||
|
return expect(request.get('/foo'), 'to be rejected').then((error) => {
|
||||||
|
expect(error, 'to be an', RequestAbortedError);
|
||||||
|
expect(error.error, 'to be', resp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should wrap "Failed to fetch" errors', () => {
|
||||||
|
const resp = new TypeError('Failed to fetch');
|
||||||
|
|
||||||
|
fetch.returns(Promise.resolve(resp));
|
||||||
|
|
||||||
|
return expect(request.get('/foo'), 'to be rejected').then((error) => {
|
||||||
|
expect(error, 'to be an', RequestAbortedError);
|
||||||
|
expect(error.message, 'to be', resp.message);
|
||||||
|
expect(error.error, 'to be', resp);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#buildQuery', () => {
|
describe('#buildQuery', () => {
|
||||||
@ -63,7 +71,8 @@ describe('services/request', () => {
|
|||||||
positive: true,
|
positive: true,
|
||||||
negative: false
|
negative: false
|
||||||
};
|
};
|
||||||
const expectedQs = 'notSet=¬Set2=&numeric=1&complexString=sdfgs%20sdfg%20&positive=1&negative=0';
|
const expectedQs
|
||||||
|
= 'notSet=¬Set2=&numeric=1&complexString=sdfgs%20sdfg%20&positive=1&negative=0';
|
||||||
|
|
||||||
expect(request.buildQuery(data), 'to equal', expectedQs);
|
expect(request.buildQuery(data), 'to equal', expectedQs);
|
||||||
});
|
});
|
||||||
|
@ -33,8 +33,7 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
beforeEach(() =>
|
beforeEach(() =>
|
||||||
localStorage.setItem('redux-storage', JSON.stringify(multiAccount))
|
localStorage.setItem('redux-storage', JSON.stringify(multiAccount)));
|
||||||
);
|
|
||||||
|
|
||||||
it('should ask for password', () => {
|
it('should ask for password', () => {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
@ -52,8 +51,7 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
|
|
||||||
cy.url().should('include', '/password');
|
cy.url().should('include', '/password');
|
||||||
|
|
||||||
cy
|
cy.get('[data-e2e-toolbar] a')
|
||||||
.get('[data-e2e-toolbar] a')
|
|
||||||
.contains('Ely.by')
|
.contains('Ely.by')
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
@ -70,13 +68,11 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
|
|
||||||
cy.url().should('include', '/choose-account');
|
cy.url().should('include', '/choose-account');
|
||||||
|
|
||||||
cy
|
cy.get('[data-e2e-content]')
|
||||||
.get('[data-e2e-content]')
|
|
||||||
.contains(account2.email)
|
.contains(account2.email)
|
||||||
.should('not.exist');
|
.should('not.exist');
|
||||||
|
|
||||||
cy
|
cy.get('[data-e2e-content]')
|
||||||
.get('[data-e2e-content]')
|
|
||||||
.contains(account1.username)
|
.contains(account1.username)
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
@ -85,13 +81,8 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('it should redirect to login, when one account and clicking back', () => {
|
it('it should redirect to login, when one account and clicking back', () => {
|
||||||
cy
|
cy.url().should(() =>
|
||||||
.url()
|
localStorage.setItem('redux-storage', JSON.stringify(singleAccount))
|
||||||
.should(() =>
|
|
||||||
localStorage.setItem(
|
|
||||||
'redux-storage',
|
|
||||||
JSON.stringify(singleAccount)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
|
|
||||||
@ -107,24 +98,26 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
it('should allow logout', () => {
|
it('should allow logout', () => {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
|
|
||||||
cy
|
cy.get('@fetch', { timeout: 15000 }).should(
|
||||||
.get('[data-e2e-toolbar]')
|
'be.calledWith',
|
||||||
|
'/api/accounts/current'
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.get('[data-e2e-toolbar]')
|
||||||
.contains(account2.username)
|
.contains(account2.username)
|
||||||
.click();
|
.click();
|
||||||
cy
|
cy.get('[data-e2e-toolbar]')
|
||||||
.get('[data-e2e-toolbar]')
|
|
||||||
.contains('Log out')
|
.contains('Log out')
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
cy
|
cy.get('@fetch', { timeout: 15000 }).should(
|
||||||
.get('@fetch', { timeout: 15000 })
|
'be.calledWith',
|
||||||
.should('be.calledWith', '/api/authentication/logout');
|
'/api/authentication/logout'
|
||||||
cy
|
);
|
||||||
.get('[data-e2e-toolbar]')
|
cy.get('[data-e2e-toolbar]')
|
||||||
.contains(account2.email)
|
.contains(account2.email)
|
||||||
.should('not.exist');
|
.should('not.exist');
|
||||||
cy
|
cy.get('[data-e2e-toolbar]')
|
||||||
.get('[data-e2e-toolbar]')
|
|
||||||
.contains(account2.username)
|
.contains(account2.username)
|
||||||
.should('not.exist');
|
.should('not.exist');
|
||||||
});
|
});
|
||||||
@ -132,6 +125,11 @@ 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.visit('/');
|
cy.visit('/');
|
||||||
|
|
||||||
|
cy.get('@fetch', { timeout: 15000 }).should(
|
||||||
|
'be.calledWith',
|
||||||
|
'/api/accounts/current'
|
||||||
|
);
|
||||||
|
|
||||||
cy.url().should('include', '/password');
|
cy.url().should('include', '/password');
|
||||||
|
|
||||||
cy.get('[data-e2e-go-back]').click();
|
cy.get('[data-e2e-go-back]').click();
|
||||||
@ -169,9 +167,7 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should ask for password if selected account with bad token', () => {
|
it('should ask for password if selected account with bad token', () => {
|
||||||
cy
|
cy.url().should(() =>
|
||||||
.url()
|
|
||||||
.should(() =>
|
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'redux-storage',
|
'redux-storage',
|
||||||
JSON.stringify(multiAccountWithBadTokens)
|
JSON.stringify(multiAccountWithBadTokens)
|
||||||
@ -183,8 +179,7 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
|
|
||||||
cy.url().should('include', '/choose-account');
|
cy.url().should('include', '/choose-account');
|
||||||
|
|
||||||
cy
|
cy.get('[data-e2e-content]')
|
||||||
.get('[data-e2e-content]')
|
|
||||||
.contains(account1.username)
|
.contains(account1.username)
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
@ -213,7 +208,7 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
*
|
*
|
||||||
* @see https://trello.com/c/iINbZ2l2
|
* @see https://trello.com/c/iINbZ2l2
|
||||||
*/
|
*/
|
||||||
it('should allow enter register page', () => {
|
it('should allow enter register page during password request for other account with invalid token', () => {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
|
|
||||||
cy.url().should('contain', '/password');
|
cy.url().should('contain', '/password');
|
||||||
@ -223,8 +218,6 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
cy.contains('[type=submit]', 'Log into another account').click();
|
cy.contains('[type=submit]', 'Log into another account').click();
|
||||||
cy.contains('a', 'Create new account').click();
|
cy.contains('a', 'Create new account').click();
|
||||||
|
|
||||||
cy.get('@fetch').should('be.calledWith', '/api/options');
|
|
||||||
|
|
||||||
cy.url().should('contain', '/register');
|
cy.url().should('contain', '/register');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -241,11 +234,9 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
*
|
*
|
||||||
* @see https://trello.com/c/iINbZ2l2
|
* @see https://trello.com/c/iINbZ2l2
|
||||||
*/
|
*/
|
||||||
it('should allow enter register page', () => {
|
it('should allow enter register page, when current account has invalid token', () => {
|
||||||
cy.visit('/register');
|
cy.visit('/register');
|
||||||
|
|
||||||
cy.get('@fetch').should('be.calledWith', '/api/options');
|
|
||||||
|
|
||||||
cy.url().should('contain', '/register');
|
cy.url().should('contain', '/register');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -260,8 +251,7 @@ describe('when user\'s token and refreshToken are invalid', () => {
|
|||||||
|
|
||||||
cy.url({ timeout: 15000 }).should('contain', '/oauth/choose-account');
|
cy.url({ timeout: 15000 }).should('contain', '/oauth/choose-account');
|
||||||
|
|
||||||
cy
|
cy.get('[data-e2e-content]')
|
||||||
.get('[data-e2e-content]')
|
|
||||||
.contains(account2.username)
|
.contains(account2.username)
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user