Skip to content

Commit

Permalink
fix(@aws-amplify/auth): Fix react-native oauth signout (aws-amplify#6376
Browse files Browse the repository at this point in the history
)

* fix(@aws-amplify/auth): Fix react-native oauth signout
  • Loading branch information
elorzafe authored Jul 21, 2020
1 parent a7feace commit c27b816
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 47 deletions.
180 changes: 135 additions & 45 deletions packages/auth/__tests__/hosted-ui.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ jest.mock('amazon-cognito-identity-js/lib/CognitoUser', () => {
return CognitoUser;
});

import { Hub, Credentials, StorageHelper } from '@aws-amplify/core';
import { Hub, Credentials, StorageHelper, JS } from '@aws-amplify/core';

const authOptionsWithOAuth: AuthOptions = {
userPoolId: 'awsUserPoolsId',
Expand Down Expand Up @@ -189,6 +189,7 @@ import { AuthOptions } from '../src/types';
describe('Hosted UI tests', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});

test('hosted UI in progress, signIn success', done => {
Expand All @@ -197,18 +198,18 @@ describe('Hosted UI tests', () => {
Username: 'username',
Pool: userPool,
});
const spyon = jest
const spyonGetCurrentUser = jest
.spyOn(CognitoUserPool.prototype, 'getCurrentUser')
.mockImplementationOnce(() => {
return user;
});
const spyon2 = jest
jest
.spyOn(CognitoUser.prototype, 'getSession')
.mockImplementation(callback => {
return callback(null, session);
});

const spyon3 = jest
jest
.spyOn(CognitoUser.prototype, 'getUserData')
.mockImplementationOnce(callback => {
const data = {
Expand All @@ -218,13 +219,13 @@ describe('Hosted UI tests', () => {
callback(null, data);
});

const spyon4 = jest
jest
.spyOn(CognitoUserSession.prototype, 'getAccessToken')
.mockImplementationOnce(() => {
return new CognitoAccessToken({ AccessToken: 'accessToken' });
});

const spyon5 = jest
jest
.spyOn(CognitoAccessToken.prototype, 'decodePayload')
.mockImplementation(() => {
return { scope: '' };
Expand All @@ -236,7 +237,7 @@ describe('Hosted UI tests', () => {

auth.currentUserPoolUser().then(resUser => {
expect(resUser).toEqual(user);
expect(spyon).toBeCalledTimes(1);
expect(spyonGetCurrentUser).toBeCalledTimes(1);
done();
});

Expand All @@ -247,7 +248,7 @@ describe('Hosted UI tests', () => {
}, 0);
});

test('globalSignOut hosted ui, timeout reject', async () => {
test('globalSignOut hosted ui on browser, timeout reject', async () => {
jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => {
return {
setItem() {},
Expand All @@ -258,26 +259,29 @@ describe('Hosted UI tests', () => {
};
});

jest.spyOn(JS, 'browserOrNode').mockImplementation(() => ({
isBrowser: true,
isNode: false,
}));

const auth = new Auth(authOptionsWithOAuth);

const user = new CognitoUser({
Username: 'username',
Pool: userPool,
});

const spyonAuth = jest
.spyOn(Credentials, 'clear')
.mockImplementationOnce(() => {
return Promise.resolve();
});
jest.spyOn(Credentials, 'clear').mockImplementationOnce(() => {
return Promise.resolve();
});

const spyon = jest
jest
.spyOn(CognitoUserPool.prototype, 'getCurrentUser')
.mockImplementationOnce(() => {
return user;
});

const spyon2 = jest
const spyGlobalSignOut = jest
.spyOn(CognitoUser.prototype, 'globalSignOut')
.mockImplementation(({ onSuccess }) => {
onSuccess('success');
Expand All @@ -298,14 +302,63 @@ describe('Hosted UI tests', () => {
expect(err).toEqual('Signout timeout fail');
}

expect(spyon2).toBeCalled();
expect(spyGlobalSignOut).toBeCalled();
});
test('globalSignOut hosted ui on node, resolve undefined', async () => {
jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => {
return {
setItem() {},
getItem() {
return 'true';
},
removeItem() {},
};
});

jest.spyOn(JS, 'browserOrNode').mockImplementation(() => ({
isBrowser: false,
isNode: true,
}));

spyonAuth.mockClear();
spyon.mockClear();
spyon2.mockClear();
const auth = new Auth(authOptionsWithOAuth);

const user = new CognitoUser({
Username: 'username',
Pool: userPool,
});

jest.spyOn(Credentials, 'clear').mockImplementationOnce(() => {
return Promise.resolve();
});

jest
.spyOn(CognitoUserPool.prototype, 'getCurrentUser')
.mockImplementationOnce(() => {
return user;
});

const spyGlobalSignOut = jest
.spyOn(CognitoUser.prototype, 'globalSignOut')
.mockImplementation(({ onSuccess }) => {
onSuccess('success');
});

auth._oAuthHandler = {
signOut: () => {
// testing timeout
return new Promise(() => {});
},
};

expect.assertions(2);

const result = await auth.signOut({ global: true });
expect(result).toBe(undefined);

expect(spyGlobalSignOut).toBeCalled();
});

test('SignOut hosted ui, timeout reject', async () => {
test('SignOut hosted ui on node, resolve undefined', async () => {
jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => {
return {
setItem() {},
Expand All @@ -316,20 +369,69 @@ describe('Hosted UI tests', () => {
};
});

jest.spyOn(JS, 'browserOrNode').mockImplementation(() => ({
isBrowser: false,
isNode: true,
}));

const auth = new Auth(authOptionsWithOAuth);

const user = new CognitoUser({
Username: 'username',
Pool: userPool,
});

const spyonAuth = jest
.spyOn(Credentials, 'clear')
jest.spyOn(Credentials, 'clear').mockImplementationOnce(() => {
return Promise.resolve();
});

jest
.spyOn(CognitoUserPool.prototype, 'getCurrentUser')
.mockImplementationOnce(() => {
return Promise.resolve();
return user;
});

const spyon = jest
auth._oAuthHandler = {
signOut: () => {
// testing timeout
return new Promise(() => {});
},
};

expect.assertions(1);

const signoutResult = await auth.signOut({ global: false }); // return undefined on node
expect(signoutResult).toBe(undefined);
});

test('SignOut hosted ui on WebBrowser, timeout reject', async () => {
jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => {
return {
setItem() {},
getItem() {
return 'true';
},
removeItem() {},
};
});

jest.spyOn(JS, 'browserOrNode').mockImplementation(() => ({
isBrowser: true,
isNode: false,
}));

const auth = new Auth(authOptionsWithOAuth);

const user = new CognitoUser({
Username: 'username',
Pool: userPool,
});

jest.spyOn(Credentials, 'clear').mockImplementationOnce(() => {
return Promise.resolve();
});

jest
.spyOn(CognitoUserPool.prototype, 'getCurrentUser')
.mockImplementationOnce(() => {
return user;
Expand All @@ -349,10 +451,8 @@ describe('Hosted UI tests', () => {
} catch (err) {
expect(err).toEqual('Signout timeout fail');
}

spyonAuth.mockClear();
spyon.mockClear();
});

test('globalSignOut hosted ui, url opener', done => {
jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => {
return {
Expand Down Expand Up @@ -389,13 +489,11 @@ describe('Hosted UI tests', () => {
Pool: userPool,
});

const spyonAuth = jest
.spyOn(Credentials, 'clear')
.mockImplementationOnce(() => {
return Promise.resolve();
});
jest.spyOn(Credentials, 'clear').mockImplementationOnce(() => {
return Promise.resolve();
});

const spyon = jest
jest
.spyOn(CognitoUserPool.prototype, 'getCurrentUser')
.mockImplementationOnce(() => {
return user;
Expand All @@ -404,9 +502,6 @@ describe('Hosted UI tests', () => {
expect.assertions(1);

auth.signOut({ global: true });

spyonAuth.mockClear();
spyon.mockClear();
});

test('SignOut hosted ui, urlOpener', done => {
Expand Down Expand Up @@ -443,13 +538,11 @@ describe('Hosted UI tests', () => {
Pool: userPool,
});

const spyonAuth = jest
.spyOn(Credentials, 'clear')
.mockImplementationOnce(() => {
return Promise.resolve();
});
jest.spyOn(Credentials, 'clear').mockImplementationOnce(() => {
return Promise.resolve();
});

const spyon = jest
jest
.spyOn(CognitoUserPool.prototype, 'getCurrentUser')
.mockImplementationOnce(() => {
return user;
Expand All @@ -458,8 +551,5 @@ describe('Hosted UI tests', () => {
expect.assertions(1);

auth.signOut({ global: true });

spyonAuth.mockClear();
spyon.mockClear();
});
});
22 changes: 20 additions & 2 deletions packages/auth/src/Auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1480,7 +1480,7 @@ export class AuthClass {
onSuccess: data => {
logger.debug('global sign out success');
if (isSignedInHostedUI) {
this.oAuthSignOutRedirectOrReject(rej);
this.oAuthSignOutRedirect(res, rej);
} else {
return res();
}
Expand All @@ -1495,14 +1495,32 @@ export class AuthClass {
logger.debug('user sign out', user);
user.signOut();
if (isSignedInHostedUI) {
this.oAuthSignOutRedirectOrReject(rej);
this.oAuthSignOutRedirect(res, rej);
} else {
return res();
}
}
});
}

private oAuthSignOutRedirect(
resolve: () => void,
reject: (reason?: any) => void
) {
const { isBrowser } = JS.browserOrNode();

if (isBrowser) {
this.oAuthSignOutRedirectOrReject(reject);
} else {
this.oAuthSignOutAndResolve(resolve);
}
}

private oAuthSignOutAndResolve(resolve: () => void) {
this._oAuthHandler.signOut();
resolve();
}

private oAuthSignOutRedirectOrReject(reject: (reason?: any) => void) {
this._oAuthHandler.signOut(); // this method redirects url

Expand Down

0 comments on commit c27b816

Please sign in to comment.