Skip to content

Commit

Permalink
Reverts - Adds Response Time out Error to RN SDKs
Browse files Browse the repository at this point in the history
  • Loading branch information
Ariflo committed Mar 15, 2024
1 parent 4f31841 commit be42797
Show file tree
Hide file tree
Showing 8 changed files with 5 additions and 264 deletions.
7 changes: 0 additions & 7 deletions packages/@magic-sdk/provider/src/core/sdk-exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,6 @@ export function createModalNotReadyError() {
return new MagicSDKError(SDKErrorCode.ModalNotReady, 'Modal is not ready.');
}

export function createResponseTimeoutError(methodType: string, messageId: number) {
return new MagicSDKError(
SDKErrorCode.ResponseTimeout,
`Response timed out for method: ${methodType} with message id: ${messageId}`,
);
}

export function createMalformedResponseError() {
return new MagicSDKError(SDKErrorCode.MalformedResponse, 'Response from the Magic iframe is malformed.');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ test('Creates a `MODAL_NOT_READY` error', async () => {
errorAssertions(error, 'MODAL_NOT_READY', 'Modal is not ready.');
});

test('Creates a `RESPONSE_TIMEOUT` error', async () => {
const { createResponseTimeoutError } = require('../../../../src/core/sdk-exceptions');
const error = createResponseTimeoutError('test_method', 123);
errorAssertions(error, 'RESPONSE_TIMEOUT', 'Response timed out for method: test_method with message id: 123');
});

test('Creates a `MALFORMED_RESPONSE` error', async () => {
const { createMalformedResponseError } = require('../../../../src/core/sdk-exceptions');
const error = createMalformedResponseError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@

import browserEnv from '@ikscodes/browser-env';
import { MagicIncomingWindowMessage, MagicOutgoingWindowMessage, JsonRpcRequestPayload } from '@magic-sdk/types';
import { create } from 'lodash';
import { createViewController, TestViewController } from '../../../factories';
import { JsonRpcResponse } from '../../../../src/core/json-rpc';
import * as storage from '../../../../src/util/storage';
import * as webCryptoUtils from '../../../../src/util/web-crypto';
import * as deviceShareWebCryptoUtils from '../../../../src/util/device-share-web-crypto';
import { SDKEnvironment } from '../../../../src/core/sdk-environment';
import { createModalNotReadyError, createResponseTimeoutError } from '../../../../src/core/sdk-exceptions';
import { createModalNotReadyError } from '../../../../src/core/sdk-exceptions';

/**
* Create a dummy request payload.
Expand Down Expand Up @@ -263,24 +262,6 @@ test('throws MODAL_NOT_READY error when not connected to the internet', async ()
}
});

test('throws RESPONSE_TIMEOUT error if response takes longer than 10 seconds', async () => {
const eventWithRt = { data: { ...responseEvent().data } };
const { handlerSpy, onSpy } = stubViewController(viewController, [
[MagicIncomingWindowMessage.MAGIC_HANDLE_RESPONSE, eventWithRt],
]);

// @ts-ignore protected variable
viewController.responseTimeout = 1;

const payload = requestPayload();

try {
await viewController.post(MagicOutgoingWindowMessage.MAGIC_HANDLE_REQUEST, payload);
} catch (e) {
expect(e).toEqual(createResponseTimeoutError('eth_accounts', 1));
}
});

test('does not call web crypto api if platform is not web', async () => {
SDKEnvironment.platform = 'react-native';
const eventWithRt = { data: { ...responseEvent().data } };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState, useCallback, useMemo, useEffect } from 'react';
import { Linking, StyleSheet, View } from 'react-native';
import { WebView } from 'react-native-webview';
import { SafeAreaView } from 'react-native-safe-area-context';
import { ViewController, createModalNotReadyError, createResponseTimeoutError } from '@magic-sdk/provider';
import { ViewController, createModalNotReadyError } from '@magic-sdk/provider';
import { MagicMessageEvent } from '@magic-sdk/types';
import { isTypedArray } from 'lodash';
import Global = NodeJS.Global;
Expand Down Expand Up @@ -62,7 +62,6 @@ export class ReactNativeWebViewController extends ViewController {
private webView!: WebView | null;
private container!: ViewWrapper | null;
private styles: any;
private messageTimeouts = new Map();

protected init() {
this.webView = null;
Expand Down Expand Up @@ -140,18 +139,6 @@ export class ReactNativeWebViewController extends ViewController {
}, [show]);

const handleWebViewMessage = useCallback((event: any) => {
const data = JSON.parse(event.nativeEvent.data);

if (data?.response?.id) {
const messageId = data.response.id;

// Clear timeout if message is received in time
if (this.messageTimeouts.has(messageId)) {
clearTimeout(this.messageTimeouts.get(messageId));
this.messageTimeouts.delete(messageId);
}
}
// Process the received message
this.handleReactNativeWebViewMessage(event);
}, []);

Expand Down Expand Up @@ -229,22 +216,7 @@ export class ReactNativeWebViewController extends ViewController {
}

protected async _post(data: any) {
// Safely access `method` and `id` from `payload`, defaulting to undefined if not present
const methodType = data.payload?.method;
const messageId = data.payload?.id;

if (this.webView && (this.webView as any).postMessage) {
// Setup timeout for message response
if (methodType && messageId) {
const timeout = setTimeout(() => {
this.messageTimeouts.delete(messageId);

throw createResponseTimeoutError(methodType, messageId);
}, 10000); // 10-second timeout

this.messageTimeouts.set(messageId, timeout);
}

(this.webView as any).postMessage(
JSON.stringify(data, (key, value) => {
// parse Typed Array to Stringify object
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import browserEnv from '@ikscodes/browser-env';
import { createModalNotReadyError, createResponseTimeoutError } from '@magic-sdk/provider';
import { SDKErrorCode } from '@magic-sdk/types';
import { createModalNotReadyError } from '@magic-sdk/provider';
import { createReactNativeWebViewController } from '../../factories';
import { reactNativeStyleSheetStub } from '../../mocks';

Expand Down Expand Up @@ -51,88 +50,3 @@ test('Process Typed Array in a Solana Request', async () => {
'https://example.com',
]);
});

test('Throws RESPONSE_TIMEOUT error if response takes longer than 10 seconds', async () => {
const overlay = createReactNativeWebViewController('https://example.com');

const postStub = jest.fn();
overlay.webView = { postMessage: postStub };

// Assume `_post` method returns a promise that rejects upon timeout
const payload = { method: 'testMethod', id: 123 };

try {
await overlay._post({ msgType: 'MAGIC_HANDLE_REQUEST-troll', payload });
} catch (error) {
expect(error.code).toBe(SDKErrorCode.ResponseTimeout);
}
});

test('Adds a timeout to messageTimeouts map on message send', async () => {
const overlay = createReactNativeWebViewController('https://example.com');

overlay.webView = { postMessage: jest.fn() };
const payload = { method: 'testMethod', id: 123 };

try {
await overlay._post({ msgType: 'MAGIC_HANDLE_REQUEST-troll', payload });
} catch (error) {
expect(error.code).toBe(SDKErrorCode.ResponseTimeout);
}

expect(overlay.messageTimeouts.has(123)).toBe(true);
});

test('Removes timeout from messageTimeouts map on response', async () => {
const overlay = createReactNativeWebViewController('https://example.com');

// Mock the WebView and its postMessage method
overlay.webView = { postMessage: jest.fn() };

const payload = { method: 'testMethod', id: 123 };
try {
await overlay._post({ msgType: 'MAGIC_HANDLE_REQUEST-troll', payload });
} catch (error) {
expect(error.code).toBe(SDKErrorCode.ResponseTimeout);
}

try {
// Simulate receiving a response by directly invoking the message handler
overlay.handleReactNativeWebViewMessage({
nativeEvent: {
data: JSON.stringify({ response: { id: 123 } }),
},
});
} catch (e) {
console.log(e);
}

expect(overlay.messageTimeouts.has(123)).toBe(true);
});

test('Removes timeout from messageTimeouts map on timeout', async () => {
expect.assertions(2); // Make sure both assertions are checked
const overlay = createReactNativeWebViewController('https://example.com');

overlay.webView = { postMessage: jest.fn() };

// Mock setTimeout to immediately invoke its callback to simulate a timeout
jest.spyOn(global, 'setTimeout').mockImplementationOnce((cb) => {
cb();
return 123; // Return a mock timer ID
});

const payload = { method: 'testMethod', id: 123 };

try {
await overlay._post({ msgType: 'MAGIC_HANDLE_REQUEST-troll', payload });
} catch (error) {
// Expect that the error was thrown due to a timeout
expect(error.code).toBe(SDKErrorCode.ResponseTimeout);
// Expect that the timeout was removed from the map after the error was thrown
expect(overlay.messageTimeouts.has(123)).toBe(false);
}

// Restore original setTimeout function
jest.restoreAllMocks();
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState, useCallback, useMemo, useEffect } from 'react';
import { Linking, StyleSheet, View } from 'react-native';
import { WebView } from 'react-native-webview';
import { SafeAreaView } from 'react-native-safe-area-context';
import { ViewController, createModalNotReadyError, createResponseTimeoutError } from '@magic-sdk/provider';
import { ViewController, createModalNotReadyError } from '@magic-sdk/provider';
import { MagicMessageEvent } from '@magic-sdk/types';
import { isTypedArray } from 'lodash';
import Global = NodeJS.Global;
Expand Down Expand Up @@ -62,7 +62,6 @@ export class ReactNativeWebViewController extends ViewController {
private webView!: WebView | null;
private container!: ViewWrapper | null;
private styles: any;
private messageTimeouts = new Map();

protected init() {
this.webView = null;
Expand Down Expand Up @@ -140,18 +139,6 @@ export class ReactNativeWebViewController extends ViewController {
}, [show]);

const handleWebViewMessage = useCallback((event: any) => {
const data = JSON.parse(event.nativeEvent.data);

if (data?.response?.id) {
const messageId = data.response.id;

// Clear timeout if message is received in time
if (this.messageTimeouts.has(messageId)) {
clearTimeout(this.messageTimeouts.get(messageId));
this.messageTimeouts.delete(messageId);
}
}
// Process the received message
this.handleReactNativeWebViewMessage(event);
}, []);

Expand Down Expand Up @@ -229,21 +216,7 @@ export class ReactNativeWebViewController extends ViewController {
}

protected async _post(data: any) {
// Safely access `method` and `id` from `payload`, defaulting to undefined if not present
const methodType = data.payload?.method;
const messageId = data.payload?.id;

if (this.webView && (this.webView as any).postMessage) {
// Setup timeout for message response
if (methodType && messageId) {
const timeout = setTimeout(() => {
this.messageTimeouts.delete(messageId);
throw createResponseTimeoutError(methodType, messageId);
}, 10000); // 10-second timeout

this.messageTimeouts.set(messageId, timeout);
}

(this.webView as any).postMessage(
JSON.stringify(data, (key, value) => {
// parse Typed Array to Stringify object
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import browserEnv from '@ikscodes/browser-env';
import { createModalNotReadyError, createResponseTimeoutError } from '@magic-sdk/provider';
import { SDKErrorCode } from '@magic-sdk/types';
import { createModalNotReadyError } from '@magic-sdk/provider';
import { createReactNativeWebViewController } from '../../factories';
import { reactNativeStyleSheetStub } from '../../mocks';

Expand Down Expand Up @@ -51,87 +50,3 @@ test('Process Typed Array in a Solana Request', async () => {
'https://example.com',
]);
});

test('Throws RESPONSE_TIMEOUT error if response takes longer than 10 seconds', async () => {
const overlay = createReactNativeWebViewController('https://example.com');
const postStub = jest.fn();
overlay.webView = { postMessage: postStub };

// Assume `_post` method returns a promise that rejects upon timeout
const payload = { method: 'testMethod', id: 123 };

try {
await overlay._post({ msgType: 'MAGIC_HANDLE_REQUEST-troll', payload });
} catch (error) {
expect(error.code).toBe(SDKErrorCode.ResponseTimeout);
}
});

test('Adds a timeout to messageTimeouts map on message send', async () => {
const overlay = createReactNativeWebViewController('https://example.com');

overlay.webView = { postMessage: jest.fn() };
const payload = { method: 'testMethod', id: 123 };

try {
await overlay._post({ msgType: 'MAGIC_HANDLE_REQUEST-troll', payload });
} catch (error) {
expect(error.code).toBe(SDKErrorCode.ResponseTimeout);
}

expect(overlay.messageTimeouts.has(123)).toBe(true);
});

test('Removes timeout from messageTimeouts map on response', async () => {
const overlay = createReactNativeWebViewController('https://example.com');

// Mock the WebView and its postMessage method
overlay.webView = { postMessage: jest.fn() };

const payload = { method: 'testMethod', id: 123 };
try {
await overlay._post({ msgType: 'MAGIC_HANDLE_REQUEST-troll', payload });
} catch (error) {
expect(error.code).toBe(SDKErrorCode.ResponseTimeout);
}

try {
// Simulate receiving a response by directly invoking the message handler
overlay.handleReactNativeWebViewMessage({
nativeEvent: {
data: JSON.stringify({ response: { id: 123 } }),
},
});
} catch (e) {
console.log(e);
}

expect(overlay.messageTimeouts.has(123)).toBe(true);
});

test('Removes timeout from messageTimeouts map on timeout', async () => {
expect.assertions(2); // Make sure both assertions are checked
const overlay = createReactNativeWebViewController('https://example.com');

overlay.webView = { postMessage: jest.fn() };

// Mock setTimeout to immediately invoke its callback to simulate a timeout
jest.spyOn(global, 'setTimeout').mockImplementationOnce((cb) => {
cb();
return 123; // Return a mock timer ID
});

const payload = { method: 'testMethod', id: 123 };

try {
await overlay._post({ msgType: 'MAGIC_HANDLE_REQUEST-troll', payload });
} catch (error) {
// Expect that the error was thrown due to a timeout
expect(error.code).toBe(SDKErrorCode.ResponseTimeout);
// Expect that the timeout was removed from the map after the error was thrown
expect(overlay.messageTimeouts.has(123)).toBe(false);
}

// Restore original setTimeout function
jest.restoreAllMocks();
});
1 change: 0 additions & 1 deletion packages/@magic-sdk/types/src/core/exception-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export enum SDKErrorCode {
InvalidArgument = 'INVALID_ARGUMENT',
ExtensionNotInitialized = 'EXTENSION_NOT_INITIALIZED',
IncompatibleExtensions = 'INCOMPATIBLE_EXTENSIONS',
ResponseTimeout = 'RESPONSE_TIMEOUT',
}

export enum SDKWarningCode {
Expand Down

0 comments on commit be42797

Please sign in to comment.