Skip to content

Commit

Permalink
refactor: Added getUserOrLogin method to authManager
Browse files Browse the repository at this point in the history
  • Loading branch information
haydenfowler authored Feb 15, 2024
1 parent d6cc5cb commit 28d4f8b
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 54 deletions.
41 changes: 33 additions & 8 deletions packages/passport/sdk/src/authManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('AuthManager', () => {
afterEach(jest.resetAllMocks);

let authManager: AuthManager;
let mockSignIn: jest.Mock;
let mockSigninPopup: jest.Mock;
let mockSigninPopupCallback: jest.Mock;
let mockSignoutRedirect: jest.Mock;
let mockGetUser: jest.Mock;
Expand All @@ -82,15 +82,15 @@ describe('AuthManager', () => {
let mockStoreUser: jest.Mock;

beforeEach(() => {
mockSignIn = jest.fn();
mockSigninPopup = jest.fn();
mockSigninPopupCallback = jest.fn();
mockSignoutRedirect = jest.fn();
mockGetUser = jest.fn();
mockSigninSilent = jest.fn();
mockSignoutSilent = jest.fn();
mockStoreUser = jest.fn();
(UserManager as jest.Mock).mockReturnValue({
signinPopup: mockSignIn,
signinPopup: mockSigninPopup,
signinPopupCallback: mockSigninPopupCallback,
signoutRedirect: mockSignoutRedirect,
signoutSilent: mockSignoutSilent,
Expand Down Expand Up @@ -160,7 +160,7 @@ describe('AuthManager', () => {
describe('login', () => {
describe('when the user has not registered for any rollup', () => {
it('should get the login user and return the domain model', async () => {
mockSignIn.mockResolvedValue(mockOidcUser);
mockSigninPopup.mockResolvedValue(mockOidcUser);

const result = await authManager.login();

Expand All @@ -170,7 +170,7 @@ describe('AuthManager', () => {

describe('when the user has registered for imx', () => {
it('should populate the imx object', async () => {
mockSignIn.mockResolvedValue({
mockSigninPopup.mockResolvedValue({
...mockOidcUser,
profile: {
...mockOidcUser.profile,
Expand All @@ -188,7 +188,7 @@ describe('AuthManager', () => {

describe('when the user has registered for zkEvm', () => {
it('should populate the zkEvm object', async () => {
mockSignIn.mockResolvedValue({
mockSigninPopup.mockResolvedValue({
...mockOidcUser,
profile: {
...mockOidcUser.profile,
Expand All @@ -206,7 +206,7 @@ describe('AuthManager', () => {

describe('when the user has registered for imx & zkEvm', () => {
it('should populate the imx & zkEvm objects', async () => {
mockSignIn.mockResolvedValue({
mockSigninPopup.mockResolvedValue({
...mockOidcUser,
profile: {
...mockOidcUser.profile,
Expand Down Expand Up @@ -235,7 +235,7 @@ describe('AuthManager', () => {
});

it('should throw the error if user is failed to login', async () => {
mockSignIn.mockRejectedValue(new Error(mockErrorMsg));
mockSigninPopup.mockRejectedValue(new Error(mockErrorMsg));

await expect(() => authManager.login()).rejects.toThrow(
new PassportError(
Expand All @@ -246,6 +246,31 @@ describe('AuthManager', () => {
});
});

describe('getUserOrLogin', () => {
describe('when getUser returns a user', () => {
it('should return the user', async () => {
mockGetUser.mockReturnValue(mockOidcUser);
(isTokenExpired as jest.Mock).mockReturnValue(false);

const result = await authManager.getUserOrLogin();

expect(result).toEqual(mockUser);
});
});

describe('when getUser throws an error', () => {
it('calls attempts to sign in the user using signinPopup', async () => {
mockGetUser.mockRejectedValue(new Error(mockErrorMsg));
mockSigninPopup.mockReturnValue(mockOidcUser);
(isTokenExpired as jest.Mock).mockReturnValue(false);

const result = await authManager.getUserOrLogin();

expect(result).toEqual(mockUser);
});
});
});

describe('loginCallback', () => {
it('should call login callback', async () => {
await authManager.loginCallback();
Expand Down
12 changes: 12 additions & 0 deletions packages/passport/sdk/src/authManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,18 @@ export default class AuthManager {
}, PassportErrorType.AUTHENTICATION_ERROR);
}

public async getUserOrLogin(): Promise<User> {
let user = null;
try {
user = await this.getUser();
} catch (err) {
// eslint-disable-next-line no-console
console.warn('failed to retrieve a cached user session:', err);
}

return user || this.login();
}

public async loginCallback(): Promise<void> {
return withPassportError<void>(
async () => this.userManager.signinPopupCallback(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { IMXClient } from '@imtbl/x-client';
import { ImxApiClients } from '@imtbl/generated-clients';
import registerPassportStarkEx from './workflows/registration';
import { PassportImxProviderFactory } from './passportImxProviderFactory';
import MagicAdapter from '../magicAdapter';
import AuthManager from '../authManager';
import { PassportError, PassportErrorType } from '../errors/passportError';
import { PassportEventMap } from '../types';
import { mockUserImx } from '../test/mocks';
import TypedEventEmitter from '../utils/typedEventEmitter';
import { PassportImxProvider } from './passportImxProvider';
import GuardianClient from '../guardian';
Expand All @@ -18,8 +16,7 @@ jest.mock('@imtbl/generated-clients');
describe('PassportImxProviderFactory', () => {
const mockAuthManager = {
getUser: jest.fn(),
forceUserRefresh: jest.fn(),
login: jest.fn(),
getUserOrLogin: jest.fn(),
};
const imxApiClients = new ImxApiClients({} as any);

Expand All @@ -41,7 +38,6 @@ describe('PassportImxProviderFactory', () => {

beforeEach(() => {
jest.restoreAllMocks();
(registerPassportStarkEx as jest.Mock).mockResolvedValue(null);
(PassportImxProvider as jest.Mock).mockImplementation(() => mockPassportImxProvider);
});

Expand All @@ -61,28 +57,25 @@ describe('PassportImxProviderFactory', () => {
describe('getProvider', () => {
describe('when the user has no idToken', () => {
it('should throw an error', async () => {
mockAuthManager.login.mockResolvedValue({ idToken: null });
mockAuthManager.getUserOrLogin.mockResolvedValue({ idToken: null });

await expect(() => passportImxProviderFactory.getProvider()).rejects.toThrow(
new PassportError(
'Failed to initialise',
PassportErrorType.WALLET_CONNECTION_ERROR,
),
);
expect(mockAuthManager.login).toHaveBeenCalledTimes(1);
expect(mockAuthManager.getUserOrLogin).toHaveBeenCalledTimes(1);
});
});

it('should return a PassportImxProvider instance if silentLogin throws error', async () => {
mockAuthManager.login.mockResolvedValue(mockUserImx);
mockAuthManager.getUser.mockRejectedValue(new Error('error'));
mockAuthManager.login.mockResolvedValue(mockUserImx);
it('should return a PassportImxProvider instance', async () => {
mockAuthManager.getUserOrLogin.mockResolvedValue({ idToken: 'id123' });

const result = await passportImxProviderFactory.getProvider();

expect(result).toBe(mockPassportImxProvider);
expect(mockAuthManager.getUser).toHaveBeenCalledTimes(1);
expect(mockAuthManager.login).toHaveBeenCalledTimes(1);
expect(registerPassportStarkEx).not.toHaveBeenCalled();
expect(mockAuthManager.getUserOrLogin).toHaveBeenCalledTimes(1);
expect(PassportImxProvider).toHaveBeenCalledWith({
magicAdapter: mockMagicAdapter,
authManager: mockAuthManager,
Expand Down
11 changes: 1 addition & 10 deletions packages/passport/sdk/src/starkEx/passportImxProviderFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,7 @@ export class PassportImxProviderFactory {
}

public async getProvider(): Promise<IMXProvider> {
let user = null;
try {
user = await this.authManager.getUser();
} catch (e) {
// eslint-disable-next-line no-console
console.warn(e);
}
if (!user) {
user = await this.authManager.login();
}
const user = await this.authManager.getUserOrLogin();
return this.createProviderInstance(user);
}

Expand Down
18 changes: 7 additions & 11 deletions packages/passport/sdk/src/zkEvm/user/loginZkEvmUser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@ jest.mock('./registerZkEvmUser');
describe('loginZkEvmUser', () => {
afterEach(jest.resetAllMocks);

const getUserMock = jest.fn();
const authLoginMock = jest.fn();
const getUserOrLoginMock = jest.fn();
const authManager = {
getUser: getUserMock,
login: authLoginMock,
getUserOrLogin: getUserOrLoginMock,
} as unknown as AuthManager;
const magicProvider = {};
const magicAdapter = {
Expand All @@ -25,7 +23,7 @@ describe('loginZkEvmUser', () => {
const multiRollupApiClients = { } as unknown as MultiRollupApiClients;

it('should return a user that has registered with zkEvm', async () => {
getUserMock.mockResolvedValue(mockUserZkEvm);
getUserOrLoginMock.mockResolvedValue(mockUserZkEvm);
const result = await loginZkEvmUser({
authManager,
magicAdapter,
Expand All @@ -37,12 +35,11 @@ describe('loginZkEvmUser', () => {
user: mockUserZkEvm,
magicProvider,
});
expect(authManager.login).toBeCalledTimes(0);
expect(registerZkEvmUser).toBeCalledTimes(0);
});

it('should register and return a user if the user has not registered with zkEvm', async () => {
authLoginMock.mockResolvedValue(mockUser);
getUserOrLoginMock.mockResolvedValue(mockUser);
(registerZkEvmUser as unknown as jest.Mock).mockResolvedValue(mockUserZkEvm);
const result = await loginZkEvmUser({
authManager,
Expand All @@ -55,12 +52,11 @@ describe('loginZkEvmUser', () => {
user: mockUserZkEvm,
magicProvider,
});
expect(authManager.login).toBeCalledTimes(1);
expect(registerZkEvmUser).toBeCalledTimes(1);
});

it('should returns a user that has invalid refresh token but login again', async () => {
(authManager.login as unknown as jest.Mock).mockResolvedValue(mockUserZkEvm);
it('should return a user that has invalid refresh token but login again', async () => {
(authManager.getUserOrLogin as unknown as jest.Mock).mockResolvedValue(mockUserZkEvm);
const result = await loginZkEvmUser({
authManager,
magicAdapter,
Expand All @@ -72,7 +68,7 @@ describe('loginZkEvmUser', () => {
user: mockUserZkEvm,
magicProvider,
});
expect(authManager.login).toBeCalledTimes(1);
expect(authManager.getUserOrLogin).toBeCalledTimes(1);
expect(registerZkEvmUser).toBeCalledTimes(0);
});
});
12 changes: 1 addition & 11 deletions packages/passport/sdk/src/zkEvm/user/loginZkEvmUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,7 @@ export const loginZkEvmUser = async ({
multiRollupApiClients,
jsonRpcProvider,
}: LoginZkEvmUserInput): Promise<LoginZkEvmUserOutput> => {
let user = null;
try {
user = await authManager.getUser();
} catch (err) {
// eslint-disable-next-line no-console
console.warn('eth_requestAccounts` failed to retrieve a cached user session:', err);
}

if (!user) {
user = await authManager.login();
}
const user = await authManager.getUserOrLogin();
if (!user.idToken) {
throw new Error('User is missing idToken');
}
Expand Down

0 comments on commit 28d4f8b

Please sign in to comment.