@reown/appkit-controllers
Version:
The full stack toolkit to build onchain app UX.
231 lines • 10.6 kB
JavaScript
import { ref } from 'valtio/vanilla';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ChainController, SIWXUtil } from '../../exports/index.js';
import { extendedMainnet, mockChainControllerState } from '../../exports/testing.js';
import { ConnectionController } from '../../src/controllers/ConnectionController.js';
import { EventsController } from '../../src/controllers/EventsController.js';
import { OptionsController } from '../../src/controllers/OptionsController.js';
import { SnackController } from '../../src/controllers/SnackController.js';
import { CoreHelperUtil } from '../../src/utils/CoreHelperUtil.js';
describe('SIWXUtil', () => {
beforeEach(() => {
vi.restoreAllMocks();
});
describe('requestSignMessage', () => {
beforeEach(() => {
vi.clearAllMocks();
mockChainControllerState({
activeCaipAddress: 'eip155:1:0x1234567890123456789012345678901234567890',
activeCaipNetwork: ref(extendedMainnet)
});
});
it('should show signature declined error and send SIWX_AUTH_ERROR event when error occurs', async () => {
const showErrorSpy = vi.spyOn(SnackController, 'showError');
const sendEventSpy = vi.spyOn(EventsController, 'sendEvent');
const getSIWXEventPropertiesSpy = vi
.spyOn(SIWXUtil, 'getSIWXEventProperties')
.mockReturnValue({
network: 'eip155:1',
isSmartAccount: false,
message: 'Test error'
});
const mockSIWX = {
createMessage: vi.fn().mockRejectedValue(new Error('Test error'))
};
vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
...OptionsController.state,
siwx: mockSIWX
});
vi.spyOn(CoreHelperUtil, 'getPlainAddress').mockReturnValue('0x1234567890123456789012345678901234567890');
vi.spyOn(ConnectionController, '_getClient').mockReturnValue({
signMessage: vi.fn()
});
await SIWXUtil.requestSignMessage();
expect(showErrorSpy).toHaveBeenCalledWith('Error signing message');
expect(sendEventSpy).toHaveBeenCalledWith({
type: 'track',
event: 'SIWX_AUTH_ERROR',
properties: {
network: 'eip155:1',
isSmartAccount: false,
message: 'Test error'
}
});
expect(getSIWXEventPropertiesSpy).toHaveBeenCalled();
});
});
describe('authConnectorAuthenticate', () => {
beforeEach(() => {
vi.clearAllMocks();
mockChainControllerState({
activeCaipAddress: 'eip155:1:0x1234567890123456789012345678901234567890',
activeCaipNetwork: ref(extendedMainnet)
});
});
it('should call authConnector.connect without siwxMessage when SIWX is not enabled', async () => {
const mockAuthConnector = {
connect: vi.fn().mockResolvedValue({
address: '0x1234567890123456789012345678901234567890',
chainId: 1,
accounts: ['0x1234567890123456789012345678901234567890']
})
};
vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
...OptionsController.state,
siwx: undefined
});
const result = await SIWXUtil.authConnectorAuthenticate({
authConnector: mockAuthConnector,
chainId: 1,
socialUri: 'test-uri',
preferredAccountType: 'eoa',
chainNamespace: 'eip155'
});
expect(mockAuthConnector.connect).toHaveBeenCalledWith({
chainId: 1,
socialUri: 'test-uri',
preferredAccountType: 'eoa'
});
expect(mockAuthConnector.connect).not.toHaveBeenCalledWith(expect.objectContaining({
siwxMessage: expect.any(Object)
}));
expect(result).toEqual({
address: '0x1234567890123456789012345678901234567890',
chainId: 1,
accounts: ['0x1234567890123456789012345678901234567890']
});
});
it('should call authConnector.connect with siwxMessage when SIWX is enabled and chainNamespace includes eip155', async () => {
const mockSiwxMessage = {
accountAddress: '',
chainId: 'eip155:1',
domain: 'example.com',
uri: 'https://example.com',
version: '1',
nonce: 'test-nonce',
notBefore: '2023-01-01T00:00:00Z',
statement: 'Sign in with Ethereum',
resources: ['https://example.com'],
requestId: 'test-request-id',
issuedAt: '2023-01-01T00:00:00Z',
expirationTime: '2023-01-02T00:00:00Z'
};
const mockSIWX = {
createMessage: vi.fn().mockResolvedValue(mockSiwxMessage)
};
const mockAuthConnector = {
connect: vi.fn().mockResolvedValue({
address: '0x1234567890123456789012345678901234567890',
chainId: 1,
accounts: ['0x1234567890123456789012345678901234567890'],
signature: '0xsignature',
message: 'test message'
})
};
const addEmbeddedWalletSessionSpy = vi
.spyOn(SIWXUtil, 'addEmbeddedWalletSession')
.mockResolvedValue();
const setLastConnectedSIWECaipNetworkSpy = vi.spyOn(ChainController, 'setLastConnectedSIWECaipNetwork');
vi.spyOn(ChainController, 'state', 'get').mockReturnValue({
...ChainController.state,
activeCaipNetwork: extendedMainnet
});
vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
...OptionsController.state,
siwx: mockSIWX
});
mockChainControllerState({
activeCaipNetwork: extendedMainnet,
chains: new Map([
[extendedMainnet.chainNamespace, { networkState: { caipNetwork: extendedMainnet } }]
])
});
const result = await SIWXUtil.authConnectorAuthenticate({
authConnector: mockAuthConnector,
chainId: 1,
socialUri: 'test-uri',
preferredAccountType: 'eoa',
chainNamespace: 'eip155'
});
expect(mockSIWX.createMessage).toHaveBeenCalledWith({
chainId: 'eip155:1',
accountAddress: '<<AccountAddress>>'
});
const completeSiwxMessage = {
...mockSiwxMessage,
accountAddress: '0x1234567890123456789012345678901234567890',
serializedMessage: 'test message'
};
expect(mockAuthConnector.connect).toHaveBeenCalledWith({
chainId: 1,
socialUri: 'test-uri',
siwxMessage: completeSiwxMessage,
preferredAccountType: 'eoa'
});
expect(addEmbeddedWalletSessionSpy).toHaveBeenCalledWith(completeSiwxMessage, 'test message', '0xsignature');
expect(result).toEqual({
address: '0x1234567890123456789012345678901234567890',
chainId: 1,
accounts: ['0x1234567890123456789012345678901234567890']
});
expect(setLastConnectedSIWECaipNetworkSpy).toHaveBeenCalledWith(extendedMainnet);
});
it('should call authConnector.connect without siwxMessage if email capture is enabled', async () => {
const mockSIWX = {
createMessage: vi.fn().mockResolvedValue({
accountAddress: '',
chainId: 'eip155:1',
domain: 'example.com',
uri: 'https://example.com',
version: '1',
nonce: 'test-nonce',
notBefore: '2023-01-01T00:00:00Z',
statement: 'Sign in with Ethereum',
resources: ['https://example.com'],
requestId: 'test-request-id',
issuedAt: '2023-01-01T00:00:00Z',
expirationTime: '2023-01-02T00:00:00Z'
})
};
const mockAuthConnector = {
connect: vi.fn().mockResolvedValue({
address: '0x1234567890123456789012345678901234567890',
chainId: 1,
accounts: ['0x1234567890123456789012345678901234567890']
})
};
// Mock OptionsController state with SIWX enabled and email capture enabled
vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
...OptionsController.state,
siwx: mockSIWX,
remoteFeatures: {
emailCapture: true
}
});
const result = await SIWXUtil.authConnectorAuthenticate({
authConnector: mockAuthConnector,
chainId: 1,
socialUri: 'test-uri',
preferredAccountType: 'eoa',
chainNamespace: 'eip155'
});
// Should call connect without siwxMessage even though SIWX is enabled
expect(mockAuthConnector.connect).toHaveBeenCalledWith({
chainId: 1,
socialUri: 'test-uri',
preferredAccountType: 'eoa'
});
expect(mockAuthConnector.connect).not.toHaveBeenCalledWith(expect.objectContaining({
siwxMessage: expect.any(Object)
}));
// Should not call createMessage since email capture bypasses SIWX flow
expect(mockSIWX.createMessage).not.toHaveBeenCalled();
expect(result).toEqual({
address: '0x1234567890123456789012345678901234567890',
chainId: 1,
accounts: ['0x1234567890123456789012345678901234567890']
});
});
});
});
//# sourceMappingURL=SIWXUtil.test.js.map