Skip to content

Commit

Permalink
[ID-1124][Passport]Add signIn function, changed connectEvm function t…
Browse files Browse the repository at this point in the history
…o call slient login first (#1057)
  • Loading branch information
carmen0208 authored Oct 27, 2023
1 parent 41b9068 commit 442c570
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import WorkflowButton from '@/components/WorkflowButton';
function PassportMethods() {
const { isLoading } = useStatusProvider();
const {
userProfile,
logout,
signIn,
getIdToken,
getAccessToken,
getUserInfo,
Expand All @@ -18,6 +20,14 @@ function PassportMethods() {
return (
<CardStack title="Passport Methods">
<Stack direction="horizontal" style={{ flexWrap: 'wrap' }} gap={3}>
{!userProfile && (
<WorkflowButton
disabled={isLoading}
onClick={signIn}
>
Login
</WorkflowButton>
)}
<WorkflowButton
disabled={isLoading}
onClick={logout}
Expand Down
27 changes: 27 additions & 0 deletions packages/passport/sdk-sample-app/src/context/PassportProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,25 @@ import { useStatusProvider } from '@/context/StatusProvider';
const PassportContext = createContext<{
imxProvider: IMXProvider | undefined;
zkEvmProvider: Provider | undefined;
userProfile: UserProfile | undefined;
connectImx:() => void;
connectImxSilent: () => void;
connectZkEvm: () => void;
logout: () => void;
signIn: () => void;
getIdToken: () => Promise<string | undefined>;
getAccessToken: () => Promise<string | undefined>;
getUserInfo: () => Promise<UserProfile | undefined>;
getLinkedAddresses: () => Promise<string[] | undefined>;
}>({
imxProvider: undefined,
zkEvmProvider: undefined,
userProfile: undefined,
connectImx: () => undefined,
connectImxSilent: () => undefined,
connectZkEvm: () => undefined,
logout: () => undefined,
signIn: () => Promise.resolve(undefined),
getIdToken: () => Promise.resolve(undefined),
getAccessToken: () => Promise.resolve(undefined),
getUserInfo: () => Promise.resolve(undefined),
Expand All @@ -35,6 +39,7 @@ export function PassportProvider({
}: { children: JSX.Element | JSX.Element[] }) {
const [imxProvider, setImxProvider] = useState<IMXProvider | undefined>();
const [zkEvmProvider, setZkEvmProvider] = useState<Provider | undefined>();
const [userProfile, setUserProfile] = useState<UserProfile | undefined>();

const { addMessage, setIsLoading } = useStatusProvider();
const { passportClient } = useImmutableProvider();
Expand Down Expand Up @@ -127,6 +132,20 @@ export function PassportProvider({
await passportClient?.logout();
setImxProvider(undefined);
setZkEvmProvider(undefined);
setUserProfile(undefined);
} catch (err) {
addMessage('Logout', err);
console.error(err);
} finally {
setIsLoading(false);
}
}, [addMessage, passportClient, setIsLoading]);

const signIn = useCallback(async () => {
try {
setIsLoading(true);
const signInuser = await passportClient?.signIn();
setUserProfile(signInuser);
} catch (err) {
addMessage('Logout', err);
console.error(err);
Expand All @@ -138,21 +157,25 @@ export function PassportProvider({
const providerValues = useMemo(() => ({
imxProvider,
zkEvmProvider,
userProfile,
connectImx,
connectImxSilent,
connectZkEvm,
logout,
signIn,
getIdToken,
getAccessToken,
getUserInfo,
getLinkedAddresses,
}), [
imxProvider,
zkEvmProvider,
userProfile,
connectImx,
connectImxSilent,
connectZkEvm,
logout,
signIn,
getIdToken,
getAccessToken,
getUserInfo,
Expand All @@ -168,23 +191,27 @@ export function PassportProvider({

export function usePassportProvider() {
const {
userProfile,
imxProvider,
zkEvmProvider,
connectImx,
connectImxSilent,
connectZkEvm,
signIn,
logout,
getIdToken,
getAccessToken,
getUserInfo,
getLinkedAddresses,
} = useContext(PassportContext);
return {
userProfile,
imxProvider,
zkEvmProvider,
connectImx,
connectImxSilent,
connectZkEvm,
signIn,
logout,
getIdToken,
getAccessToken,
Expand Down
43 changes: 42 additions & 1 deletion packages/passport/sdk/src/Passport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ConfirmationScreen } from './confirmation';
import { Passport } from './Passport';
import { PassportImxProvider, PassportImxProviderFactory } from './starkEx';
import { Networks, OidcConfiguration } from './types';
import { mockUser, mockLinkedAddresses } from './test/mocks';
import { mockUser, mockLinkedAddresses, mockUserImx } from './test/mocks';

jest.mock('./authManager');
jest.mock('./magicAdapter');
Expand Down Expand Up @@ -126,6 +126,17 @@ describe('Passport', () => {
expect(result).toBe(passportImxProvider);
expect(getProviderMock).toHaveBeenCalled();
});

it('should call getProviderSilent if useCachedSession is true', async () => {
const passportImxProvider = {} as PassportImxProvider;
getProviderSilentMock.mockResolvedValue(passportImxProvider);

const result = await passport.connectImx({ useCachedSession: true });

expect(result).toBe(passportImxProvider);
expect(getProviderSilentMock).toHaveBeenCalled();
expect(getProviderMock).not.toHaveBeenCalled();
});
});

describe('connectImxSilent', () => {
Expand Down Expand Up @@ -247,4 +258,34 @@ describe('Passport', () => {
expect(result).toHaveLength(0);
});
});

describe('signIn', () => {
it('should login silently if there is a user', async () => {
loginSilentMock.mockReturnValue(mockUserImx);
const user = await passport.signIn();

expect(loginSilentMock).toBeCalledTimes(1);
expect(authLoginMock).toBeCalledTimes(0);
expect(user).toEqual(mockUser.profile);
});

it('should signIn and get a user', async () => {
loginSilentMock.mockReturnValue(null);
authLoginMock.mockReturnValue(mockUserImx);
const user = await passport.signIn();

expect(loginSilentMock).toBeCalledTimes(1);
expect(authLoginMock).toBeCalledTimes(1);
expect(user).toEqual(mockUserImx.profile);
});

it('should only login silently if useCachedSession is true', async () => {
loginSilentMock.mockReturnValue(mockUserImx);
const user = await passport.signIn({ useCachedSession: true });

expect(loginSilentMock).toBeCalledTimes(1);
expect(authLoginMock).toBeCalledTimes(0);
expect(user).toEqual(mockUser.profile);
});
});
});
21 changes: 20 additions & 1 deletion packages/passport/sdk/src/Passport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,30 @@ export class Passport {
});
}

public async signIn(options?: { useCachedSession: boolean }): Promise<UserProfile | null> {
const { useCachedSession = false } = options || {};
let user = await this.authManager.loginSilent();
if (!user && !useCachedSession) {
user = await this.authManager.login();
}
if (!user) {
return null;
}
return user.profile;
}

/**
* @deprecated The method connectImx(useCachedSession) should be used instead
*/
public async connectImxSilent(): Promise<IMXProvider | null> {
return this.passportImxProviderFactory.getProviderSilent();
}

public async connectImx(): Promise<IMXProvider> {
public async connectImx(options?: { useCachedSession: boolean }): Promise<IMXProvider | null> {
const { useCachedSession = false } = options || {};
if (useCachedSession) {
return this.passportImxProviderFactory.getProviderSilent();
}
return this.passportImxProviderFactory.getProvider();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ describe('PassportImxProviderFactory', () => {

mockAuthManager.login.mockResolvedValue(mockUser);
mockMagicAdapter.login.mockResolvedValue(mockMagicProvider);
mockAuthManager.loginSilent.mockResolvedValueOnce(null);
mockAuthManager.loginSilent.mockResolvedValue(mockUser);

await expect(() => passportImxProviderFactory.getProvider()).rejects.toThrow(
Expand All @@ -107,10 +108,11 @@ describe('PassportImxProviderFactory', () => {
starkSigner: mockStarkSigner,
usersApi: immutableXClient.usersApi,
}, mockUser.accessToken);
expect(mockAuthManager.loginSilent).toHaveBeenCalledTimes(4);
expect(mockAuthManager.loginSilent).toHaveBeenNthCalledWith(1, { forceRefresh: true });
expect(mockAuthManager.loginSilent).toHaveBeenCalledTimes(5);
expect(mockAuthManager.loginSilent).toHaveBeenNthCalledWith(1);
expect(mockAuthManager.loginSilent).toHaveBeenNthCalledWith(2, { forceRefresh: true });
expect(mockAuthManager.loginSilent).toHaveBeenNthCalledWith(3, { forceRefresh: true });
expect(mockAuthManager.loginSilent).toHaveBeenNthCalledWith(4, { forceRefresh: true });
expect(mockAuthManager.loginSilent).toHaveBeenCalledWith({ forceRefresh: true });
});
});
Expand All @@ -121,6 +123,7 @@ describe('PassportImxProviderFactory', () => {

mockAuthManager.login.mockResolvedValue(mockUser);
mockMagicAdapter.login.mockResolvedValue(mockMagicProvider);
mockAuthManager.loginSilent.mockResolvedValueOnce(null);
mockAuthManager.loginSilent.mockResolvedValue(mockUserImx);

const result = await passportImxProviderFactory.getProvider();
Expand All @@ -134,7 +137,7 @@ describe('PassportImxProviderFactory', () => {
starkSigner: mockStarkSigner,
usersApi: immutableXClient.usersApi,
}, mockUserImx.accessToken);
expect(mockAuthManager.loginSilent).toHaveBeenCalledTimes(1);
expect(mockAuthManager.loginSilent).toHaveBeenCalledTimes(2);
expect(mockAuthManager.loginSilent).toHaveBeenCalledWith({ forceRefresh: true });
expect(PassportImxProvider).toHaveBeenCalledWith({
authManager: mockAuthManager,
Expand All @@ -154,16 +157,17 @@ describe('PassportImxProviderFactory', () => {

mockAuthManager.login.mockResolvedValue(mockUserImx);
mockMagicAdapter.login.mockResolvedValue(mockMagicProvider);
mockAuthManager.loginSilent.mockResolvedValue(mockUserImx);
mockAuthManager.loginSilent.mockResolvedValue(null);
mockAuthManager.login.mockResolvedValue(mockUserImx);

const result = await passportImxProviderFactory.getProvider();

expect(result).toBe(mockPassportImxProvider);
expect(mockAuthManager.loginSilent).toHaveBeenCalledTimes(1);
expect(mockAuthManager.login).toHaveBeenCalledTimes(1);
expect(mockMagicAdapter.login).toHaveBeenCalledWith(mockUserImx.idToken);
expect(mockGetSigner).toHaveBeenCalledTimes(1);
expect(registerPassportStarkEx).not.toHaveBeenCalled();
expect(mockAuthManager.loginSilent).not.toHaveBeenCalled();
expect(PassportImxProvider).toHaveBeenCalledWith({
authManager: mockAuthManager,
starkSigner: mockStarkSigner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class PassportImxProviderFactory {
}

public async getProvider(): Promise<PassportImxProvider> {
const user = await this.authManager.login();
const user = await this.authManager.loginSilent() || await this.authManager.login();
return this.createProviderInstance(user);
}

Expand Down

0 comments on commit 442c570

Please sign in to comment.