Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improves the react connected hook when using extension & emit terminate when using extension #1186

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { renderHook } from '@testing-library/react-hooks';
import { useHandleTerminateEvent } from './useHandleTerminateEvent';
import { EventHandlerProps } from '../MetaMaskProvider';
import * as loggerModule from '../utils/logger';

describe('useHandleTerminateEvent', () => {
const spyLogger = jest.spyOn(loggerModule, 'logger');

const eventHandlerProps = {
setConnecting: jest.fn(),
setConnected: jest.fn(),
setError: jest.fn(),
debug: true,
} as unknown as EventHandlerProps;

beforeEach(() => {
jest.clearAllMocks();

eventHandlerProps.setConnecting = jest.fn();
eventHandlerProps.setConnected = jest.fn();
eventHandlerProps.setError = jest.fn();
});

it('should handle the terminate event correctly', () => {
const mockReason = { message: 'Terminated due to xyz', code: -32000 };

const { result } = renderHook(() =>
useHandleTerminateEvent(eventHandlerProps),
);
result.current(mockReason);

expect(spyLogger).toHaveBeenCalledWith(
"[MetaMaskProvider: useHandleTerminateEvent()] on 'terminate' event.",
mockReason,
);

expect(eventHandlerProps.setConnecting).toHaveBeenCalledWith(false);
expect(eventHandlerProps.setConnected).toHaveBeenCalledWith(false);
expect(eventHandlerProps.setError).toHaveBeenCalledWith(mockReason);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { EthereumRpcError } from 'eth-rpc-errors';
import { useCallback } from 'react';
import { EventHandlerProps } from '../MetaMaskProvider';
import { logger } from '../utils/logger';

export const useHandleTerminateEvent = ({
debug,
setConnecting,
setConnected,
setError,
}: EventHandlerProps) => {
return useCallback(
(reason: unknown) => {
logger(
`[MetaMaskProvider: useHandleTerminateEvent()] on 'terminate' event.`,
reason,
);

setConnecting(false);
setConnected(false);
setError(reason as EthereumRpcError<unknown>);
},
[debug, setConnecting, setConnected, setError],
);
};
6 changes: 4 additions & 2 deletions packages/sdk-react/src/MetaMaskProvider.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ describe('MetaMaskProvider Component', () => {
});

expect(mockSdkOn).toHaveBeenCalledTimes(2);
expect(mockProviderOn).toHaveBeenCalledTimes(6);
expect(mockProviderOn).toHaveBeenCalledTimes(7);

expect(mockSdkOn.mock.calls).toEqual([
['service_status', expect.any(Function)],
Expand All @@ -126,6 +126,7 @@ describe('MetaMaskProvider Component', () => {

expect(mockProviderOn.mock.calls).toEqual([
['_initialized', expect.any(Function)],
['terminate', expect.any(Function)],
['connecting', expect.any(Function)],
['connect', expect.any(Function)],
['disconnect', expect.any(Function)],
Expand All @@ -144,7 +145,7 @@ describe('MetaMaskProvider Component', () => {
cleanup();

expect(mockSdkRemoveListener).toHaveBeenCalledTimes(2);
expect(mockProviderRemoveListener).toHaveBeenCalledTimes(6);
expect(mockProviderRemoveListener).toHaveBeenCalledTimes(7);

expect(mockSdkRemoveListener.mock.calls).toEqual([
['service_status', expect.any(Function)],
Expand All @@ -156,6 +157,7 @@ describe('MetaMaskProvider Component', () => {
['connecting', expect.any(Function)],
['connect', expect.any(Function)],
['disconnect', expect.any(Function)],
['terminate', expect.any(Function)],
['accountsChanged', expect.any(Function)],
['chainChanged', expect.any(Function)],
]);
Expand Down
12 changes: 11 additions & 1 deletion packages/sdk-react/src/MetaMaskProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import { useHandleOnConnectingEvent } from './EventsHandlers/useHandleOnConnectingEvent';
import { useHandleProviderEvent } from './EventsHandlers/useHandleProviderEvent';
import { useHandleSDKStatusEvent } from './EventsHandlers/useHandleSDKStatusEvent';
import { useHandleTerminateEvent } from './EventsHandlers/useHandleTerminateEvent';
import { logger } from './utils/logger';

export interface EventHandlerProps {
Expand Down Expand Up @@ -130,6 +131,8 @@
const onConnect = useHandleConnectEvent(eventHandlerProps);

const onDisconnect = useHandleDisconnectEvent(eventHandlerProps);

const onTerminate = useHandleTerminateEvent(eventHandlerProps);

const onAccountsChanged = useHandleAccountsChangedEvent(eventHandlerProps);

Expand Down Expand Up @@ -262,12 +265,18 @@
console.warn(`[MetaMaskProviderClient] activeProvider is undefined.`);
return;
}
setConnected(activeProvider.isConnected());

const isConnected = sdk.isExtensionActive()
? !!activeProvider.getSelectedAddress()
: activeProvider.isConnected();

Check warning on line 271 in packages/sdk-react/src/MetaMaskProvider.tsx

View check run for this annotation

Codecov / codecov/patch

packages/sdk-react/src/MetaMaskProvider.tsx#L271

Added line #L271 was not covered by tests

setConnected(isConnected);
setAccount(activeProvider.getSelectedAddress() || undefined);
setProvider(activeProvider);
setChainId(activeProvider.getChainId() || undefined);

activeProvider.on('_initialized', onInitialized);
activeProvider.on('terminate', onTerminate);
activeProvider.on('connecting', onConnecting);
activeProvider.on('connect', onConnect);
activeProvider.on('disconnect', onDisconnect);
Expand Down Expand Up @@ -296,6 +305,7 @@
activeProvider.removeListener('connecting', onConnecting);
activeProvider.removeListener('connect', onConnect);
activeProvider.removeListener('disconnect', onDisconnect);
activeProvider.removeListener('terminate', onTerminate);
activeProvider.removeListener('accountsChanged', onAccountsChanged);
activeProvider.removeListener('chainChanged', onChainChanged);
sdk.removeListener(EventType.SERVICE_STATUS, onSDKStatusEvent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('terminate', () => {
it('should not switch providers if extensionOnly option is true', async () => {
instance.options.extensionOnly = true;
await terminate(instance);
expect(mockEmit).not.toHaveBeenCalled();
expect(mockEmit).toHaveBeenCalledTimes(1);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export async function terminate(instance: MetaMaskSDK) {
}

if (instance.options.extensionOnly) {
instance.emit(
MetaMaskSDKEvent.ProviderUpdate,
PROVIDER_UPDATE_TYPE.TERMINATE,
);

logger(
`[MetaMaskSDK: terminate()] extensionOnly --- prevent switching providers`,
);
Expand Down
Loading