Skip to content

Commit

Permalink
test: add connection test code
Browse files Browse the repository at this point in the history
  • Loading branch information
jinoosss committed Sep 3, 2024
1 parent a72ea57 commit 0043fbc
Show file tree
Hide file tree
Showing 10 changed files with 355 additions and 8 deletions.
15 changes: 15 additions & 0 deletions jest.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"projects": ["<rootDir>/packages/*"],
"watchPathIgnorePatterns": ["<rootDir>/node_modules/", "<rootDir>/bin/"],
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/bin/",
"<rootDir>/**/node_modules/",
"<rootDir>/**/bin/",
"<rootDir>/**/__mocks__/",
"<rootDir>/**/coverage/"
],
"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
}
}
8 changes: 7 additions & 1 deletion packages/sdk/jest.config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
{
"preset": "ts-jest",
"testEnvironment": "node",
"modulePathIgnorePatterns": ["bin", "node_modules"]
"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
},
"testMatch": ["<rootDir>/**/*.test.(ts|tsx)"],
"moduleFileExtensions": ["ts", "tsx", "js", "jsx"],
"moduleDirectories": ["node_modules", "<rootDir>/packages"],
"modulePathIgnorePatterns": ["bin", "node_modules", "coverage", "__mocks__"]
}
11 changes: 11 additions & 0 deletions packages/sdk/src/core/__mocks__/mock-global.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { mockSessionStorage } from './mock-storage';

export const defineGlobalMock = () => {
Object.defineProperty(global, 'sessionStorage', {
value: mockSessionStorage,
});
};

export const clearGlobalMock = () => {
Object.defineProperty(global, 'sessionStorage', {});
};
18 changes: 18 additions & 0 deletions packages/sdk/src/core/__mocks__/mock-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const mockSessionStorage = (() => {
let store: Record<string, string> = {};

return {
getItem(key: string) {
return store[key] || null;
},
setItem(key: string, value: string) {
store[key] = value.toString();
},
removeItem(key: string) {
delete store[key];
},
clear() {
store = {};
},
};
})();
164 changes: 164 additions & 0 deletions packages/sdk/src/core/__mocks__/mock-wallet-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { WalletProvider } from '../providers';
import { WalletResponseFailedType, WalletResponseStatus, WalletResponseSuccessType } from '../types';

export const mockWalletProvider: jest.Mocked<WalletProvider> = {
isConnected: jest.fn().mockResolvedValue({
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.CONNECTION_SUCCESS,
message: 'Wallet is connected',
data: null,
}),
addEstablish: jest.fn().mockResolvedValue({
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.CONNECTION_SUCCESS,
message: 'Connection established',
data: null,
}),
getAccount: jest.fn().mockResolvedValue({
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.GET_ACCOUNT_SUCCESS,
message: 'Account retrieved',
data: { address: 'mock-address', connected: true },
}),
switchNetwork: jest.fn().mockResolvedValue({
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.SWITCH_NETWORK_SUCCESS,
message: 'Network switched',
data: null,
}),
addNetwork: jest.fn().mockResolvedValue({
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.ADD_NETWORK_SUCCESS,
message: 'Network added',
data: null,
}),
signTransaction: jest.fn().mockResolvedValue({
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.SIGN_SUCCESS,
message: 'Transaction signed',
data: 'mock-signed-transaction',
}),
broadcastTransaction: jest.fn().mockResolvedValue({
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.TRANSACTION_SUCCESS,
message: 'Transaction broadcasted',
data: { result: 'mock-result' },
}),
onChangeAccount: jest.fn().mockImplementation(() => {
return {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.CONNECTION_SUCCESS,
message: 'Account change listener added',
data: null,
};
}),
onChangeNetwork: jest.fn().mockImplementation(() => {
return {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.SWITCH_NETWORK_SUCCESS,
message: 'Network change listener added',
data: null,
};
}),
};

jest.mock('../providers', () => ({
WalletProvider: jest.fn(() => mockWalletProvider),
}));

export const isConnectedSuccessMock = {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.CONNECTION_SUCCESS,
message: '',
data: true,
};

export const isConnectedFailureMock = {
code: 4000,
status: WalletResponseStatus.FAILURE,
type: WalletResponseFailedType.ALREADY_CONNECTED,
message: '',
data: false,
};

export const addEstablishSuccessMock = {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.CONNECTION_SUCCESS,
message: '',
data: null,
};

export const addEstablishFailureMock = {
code: 4000,
status: WalletResponseStatus.FAILURE,
type: WalletResponseFailedType.ALREADY_CONNECTED,
message: '',
data: null,
};

export const getAccountSuccessMock = {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.GET_ACCOUNT_SUCCESS,
message: '',
data: { address: '' },
};

export const switchNetworkSuccessMock = {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.SWITCH_NETWORK_SUCCESS,
message: '',
data: null,
};

export const addNetworkSuccessMock = {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.ADD_NETWORK_SUCCESS,
message: '',
data: null,
};

export const signTransactionSuccessMock = {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.SIGN_SUCCESS,
message: '',
data: '',
};

export const broadcastTransactionSuccessMock = {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.TRANSACTION_SUCCESS,
message: '',
data: { result: '' },
};

export const onChangeAccountSuccessMock = {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.CONNECTION_SUCCESS,
message: '',
data: null,
};

export const onChangeNetworkSuccessMock = {
code: 0,
status: WalletResponseStatus.SUCCESS,
type: WalletResponseSuccessType.SWITCH_NETWORK_SUCCESS,
message: '',
data: null,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { clearGlobalMock, defineGlobalMock } from '../../__mocks__/mock-global';
import {
addEstablishFailureMock,
addEstablishSuccessMock,
isConnectedFailureMock,
isConnectedSuccessMock,
mockWalletProvider,
} from '../../__mocks__/mock-wallet-provider';
import { ConnectionManager, ConnectionState } from '../../connection';
import { SDKConnectionConfigure } from '../../types/config.types';

describe('ConnectionManager', () => {
let connectionManager: ConnectionManager;
let config: SDKConnectionConfigure;

beforeEach(() => {
defineGlobalMock();
config = { isSession: true };

// Initialize ConnectionManager with a real instance of ConnectionStateManager
connectionManager = new ConnectionManager(mockWalletProvider, config);
});

afterEach(() => {
jest.clearAllMocks();
clearGlobalMock();
});

test('should initialize and load state if isSession is true', () => {
// Initially, loadState should set the state to CONNECTED if it was not saved
connectionManager = new ConnectionManager(mockWalletProvider, config);
expect(connectionManager.getConnectionState()).toBe(ConnectionState.CONNECTED);
});

test('should set state to CONNECTING when connecting wallet', async () => {
mockWalletProvider.isConnected.mockResolvedValue(isConnectedSuccessMock);
mockWalletProvider.addEstablish.mockResolvedValue(addEstablishSuccessMock);

await connectionManager.connectWallet();

expect(connectionManager.getConnectionState()).toBe(ConnectionState.CONNECTED);
});

test('should connect wallet if already connected', async () => {
mockWalletProvider.isConnected.mockResolvedValue(isConnectedSuccessMock);

await connectionManager.connectWallet();

expect(connectionManager.getConnectionState()).toBe(ConnectionState.CONNECTED);
});

test('should set state to DISCONNECTED if connection fails', async () => {
connectionManager = new ConnectionManager(mockWalletProvider, { isSession: false });
mockWalletProvider.isConnected.mockResolvedValue(isConnectedFailureMock);
mockWalletProvider.addEstablish.mockResolvedValue(addEstablishFailureMock);

await connectionManager.connectWallet();

expect(connectionManager.getConnectionState()).toBe(ConnectionState.DISCONNECTED);
});

test('should set state to ERROR if an exception is thrown', async () => {
mockWalletProvider.isConnected.mockRejectedValueOnce(new Error('connection error'));

await expect(connectionManager.connectWallet()).rejects.toThrow('connection error');
expect(connectionManager.getConnectionState()).toBe(ConnectionState.ERROR);
});

test('should trigger connection event when connected', () => {
const listener = jest.fn();
connectionManager.on(listener);

connectionManager['connect']();

expect(connectionManager.getConnectionState()).toBe(ConnectionState.CONNECTED);
expect(listener).toHaveBeenCalledWith('connect');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { clearGlobalMock, defineGlobalMock } from '../../__mocks__/mock-global';
import { ConnectionState, ConnectionStateManager } from '../../connection';
import { getSessionStorageItem, setSessionStorageItem } from '../../utils/storage.utils';

jest.mock('../../utils/storage.utils', () => ({
getSessionStorageItem: jest.fn(),
setSessionStorageItem: jest.fn(),
}));

describe('ConnectionStateManager', () => {
let manager: ConnectionStateManager;

beforeEach(() => {
defineGlobalMock();
manager = new ConnectionStateManager();
});

afterEach(() => {
jest.clearAllMocks();
clearGlobalMock();
});

it('should initialize with DISCONNECTED state', () => {
expect(manager.getState()).toBe(ConnectionState.DISCONNECTED);
});

it('should save state to session storage when setState is called', () => {
manager.setState(ConnectionState.CONNECTED);

expect(setSessionStorageItem).toHaveBeenCalledWith(
'adena-sdk-connection-state',
ConnectionState.CONNECTED.toString()
);
expect(manager.getState()).toBe(ConnectionState.CONNECTED);
});

it('should load state from session storage when loadState is called', () => {
(getSessionStorageItem as jest.Mock).mockReturnValue(ConnectionState.CONNECTED.toString());

manager.loadState();

expect(getSessionStorageItem).toHaveBeenCalledWith('adena-sdk-connection-state');
expect(manager.getState()).toBe(ConnectionState.CONNECTED);
});

it('should not change state if the loaded state is not CONNECTED', () => {
(getSessionStorageItem as jest.Mock).mockReturnValue(ConnectionState.DISCONNECTED.toString());

manager.loadState();

expect(getSessionStorageItem).toHaveBeenCalledWith('adena-sdk-connection-state');
expect(manager.getState()).toBe(ConnectionState.DISCONNECTED);
});
});
10 changes: 5 additions & 5 deletions packages/sdk/src/core/connection/connection-manager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { isSuccessType } from '../../providers/adena-wallet/mapper.utils';
import { WalletProvider } from '../providers';
import { WalletConnectionEvent } from '../types';
import { WalletConnectionEvent, WalletResponseStatus } from '../types';
import { SDKConnectionConfigure } from '../types/config.types';
import { ConnectionState, ConnectionStateManager } from './connection-state';

Expand All @@ -12,6 +11,7 @@ export class ConnectionManager {
private provider: WalletProvider,
private config: SDKConnectionConfigure
) {
this.listeners = [];
this.stateManager = new ConnectionStateManager();
if (this.config.isSession) {
this.stateManager.loadState();
Expand All @@ -26,15 +26,15 @@ export class ConnectionManager {

try {
// If your wallet is already connected, change to connected.
const connected = await this.provider.isConnected();
if (connected) {
const isConnectedResponse = await this.provider.isConnected();
if (isConnectedResponse.status === WalletResponseStatus.SUCCESS) {
this.connect();
return;
}

// If the app is registered in your wallet, change the status to connected.
const addEstablishResponse = await this.provider.addEstablish({});
if (isSuccessType(addEstablishResponse.status)) {
if (addEstablishResponse.status === WalletResponseStatus.SUCCESS) {
this.connect();
return;
}
Expand Down
Loading

0 comments on commit 0043fbc

Please sign in to comment.