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

chore: controller tests improvements [1] #2032

Merged
merged 12 commits into from
Mar 27, 2024
Merged
12 changes: 12 additions & 0 deletions dangerfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ async function checkCorePackage() {
f.includes('core/tests/controllers')
)

const modified_core_controllers = modified_files.filter(f => f.includes('core/src/controllers'))
const modified_core_controllers_tests = modified_files.filter(f =>
f.includes('core/tests/controllers')
)

for (const f of created_core_controllers) {
const diff = await diffForFile(f)

Expand Down Expand Up @@ -214,6 +219,13 @@ async function checkCorePackage() {
if (created_core_controllers.length && !created_core_controllers_tests.length) {
fail('New controllers were added, but no tests were created')
}

if (modified_core_controllers.length && !modified_core_controllers_tests) {
message(`
The following controllers were modified, but not tests were changed:
${modified_core_controllers.join('\n')}
`)
}
}
checkCorePackage()

Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/controllers/AccountController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ type StateKey = keyof AccountControllerState
const state = proxy<AccountControllerState>({
isConnected: false,
currentTab: 0,
tokenBalance: []
tokenBalance: [],
smartAccountDeployed: false
})

// -- Controller ---------------------------------------- //
Expand Down Expand Up @@ -99,6 +100,7 @@ export const AccountController = {

resetAccount() {
state.isConnected = false
state.smartAccountDeployed = false
state.currentTab = 0
state.caipAddress = undefined
state.address = undefined
Expand All @@ -107,7 +109,6 @@ export const AccountController = {
state.profileName = undefined
state.profileImage = undefined
state.addressExplorerUrl = undefined
state.smartAccountDeployed = undefined
state.tokenBalance = []
}
}
20 changes: 18 additions & 2 deletions packages/core/tests/controllers/AccountController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@ const balance = '0.100'
const balanceSymbol = 'ETH'
const profileName = 'john.eth'
const profileImage = 'https://ipfs.com/0x123.png'
const explorerUrl = 'https://some.explorer.com/explore'

// -- Tests --------------------------------------------------------------------
describe('AccountController', () => {
it('should have valid default state', () => {
expect(AccountController.state).toEqual({ isConnected: false, tokenBalance: [], currentTab: 0 })
expect(AccountController.state).toEqual({
isConnected: false,
smartAccountDeployed: false,
currentTab: 0,
tokenBalance: []
})
})

it('should update state correctly on setIsConnected()', () => {
Expand Down Expand Up @@ -41,10 +47,21 @@ describe('AccountController', () => {
expect(AccountController.state.profileImage).toEqual(profileImage)
})

it('should update state correctly on setAddressExplorerUrl()', () => {
AccountController.setAddressExplorerUrl(explorerUrl)
expect(AccountController.state.addressExplorerUrl).toEqual(explorerUrl)
})

it('shuold update state correctly on setSmartAccountDeployed()', () => {
AccountController.setSmartAccountDeployed(true)
expect(AccountController.state.smartAccountDeployed).toEqual(true)
})

it('should update state correctly on resetAccount()', () => {
AccountController.resetAccount()
expect(AccountController.state).toEqual({
isConnected: false,
smartAccountDeployed: false,
currentTab: 0,
caipAddress: undefined,
address: undefined,
Expand All @@ -53,7 +70,6 @@ describe('AccountController', () => {
profileName: undefined,
profileImage: undefined,
addressExplorerUrl: undefined,
smartAccountDeployed: undefined,
tokenBalance: []
})
})
Expand Down
4 changes: 2 additions & 2 deletions packages/core/tests/controllers/ApiController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ describe('ApiController', () => {
expect(fetchSpy).toHaveBeenCalledTimes(2)
})

it('should fetch network images', async () => {
it('should only fetch network images for networks with imageIds', async () => {
NetworkController.setRequestedCaipNetworks([
{
id: '155:1',
Expand Down Expand Up @@ -236,7 +236,7 @@ describe('ApiController', () => {
expect(fetchImageSpy).not.toHaveBeenCalled()
})

// Recommended wllets
// Recommended wallets
it('should fetch recommended wallets with configured recommended wallets', async () => {
const includeWalletIds = ['12341', '12342']
const excludeWalletIds = ['12343']
Expand Down
93 changes: 93 additions & 0 deletions packages/core/tests/controllers/AssetController.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
import { describe, expect, it } from 'vitest'
import { AssetController } from '../../index.js'

// -- Constants ----------------------------------------------------------------
const walletImage = 'w3mWallet.png'
const walletImage2 = 'w3mWallet2.png'
const networkImage = 'ethereum.png'
const networkImage2 = 'polygon.png'
const connectorImage = 'email-connector.png'
const connectorImage2 = 'metamask-connector.png'
const tokenImage = 'eth.png'
const tokenImage2 = 'usdc.png'
const currencyImage = 'usd.png'
const currencyImage2 = 'eur.png'

const wallet = 'w3m'
const wallet2 = 'w4m'
const network = 'ethereum'
const network2 = 'polygon'
const connector = 'w3m-email'
const connector2 = 'mm-connector'
const token = 'ETH'
const token2 = 'MATIC'
const currency = 'USD'
const currency2 = 'EUR'

// -- Tests --------------------------------------------------------------------
describe('AssetController', () => {
it('should have valid default state', () => {
Expand All @@ -12,4 +35,74 @@ describe('AssetController', () => {
currencyImages: {}
})
})

it('should update state properly on setWalletImage()', () => {
AssetController.setWalletImage(wallet, walletImage)
expect(AssetController.state.walletImages).toEqual({ [wallet]: walletImage })

AssetController.setWalletImage(wallet, walletImage2)
expect(AssetController.state.walletImages).toEqual({ [wallet]: walletImage2 })

AssetController.setWalletImage(wallet2, walletImage2)
expect(AssetController.state.walletImages).toEqual({
[wallet]: walletImage2,
[wallet2]: walletImage2
})
})

it('should update state properly on setNetworkImage()', () => {
AssetController.setNetworkImage(network, networkImage)
expect(AssetController.state.networkImages).toEqual({ [network]: networkImage })

AssetController.setNetworkImage(network, networkImage2)
expect(AssetController.state.networkImages).toEqual({ [network]: networkImage2 })

AssetController.setNetworkImage(network2, networkImage2)
expect(AssetController.state.networkImages).toEqual({
[network]: networkImage2,
[network2]: networkImage2
})
})

it('should update state properly on setConnectorImage()', () => {
AssetController.setConnectorImage(connector, connectorImage)
expect(AssetController.state.connectorImages).toEqual({ [connector]: connectorImage })

AssetController.setConnectorImage(connector, connectorImage2)
expect(AssetController.state.connectorImages).toEqual({ [connector]: connectorImage2 })

AssetController.setConnectorImage(connector2, connectorImage2)
expect(AssetController.state.connectorImages).toEqual({
[connector]: connectorImage2,
[connector2]: connectorImage2
})
})

it('should update state properly on setTokenImage()', () => {
AssetController.setTokenImage(token, tokenImage)
expect(AssetController.state.tokenImages).toEqual({ [token]: tokenImage })

AssetController.setTokenImage(token, tokenImage2)
expect(AssetController.state.tokenImages).toEqual({ [token]: tokenImage2 })

AssetController.setTokenImage(token2, tokenImage2)
expect(AssetController.state.tokenImages).toEqual({
[token]: tokenImage2,
[token2]: tokenImage2
})
})

it('should update state properly on setCurrencyImage()', () => {
AssetController.setCurrencyImage(currency, currencyImage)
expect(AssetController.state.currencyImages).toEqual({ [currency]: currencyImage })

AssetController.setCurrencyImage(currency, currencyImage2)
expect(AssetController.state.currencyImages).toEqual({ [currency]: currencyImage2 })

AssetController.setCurrencyImage(currency2, currencyImage2)
expect(AssetController.state.currencyImages).toEqual({
[currency]: currencyImage2,
[currency2]: currencyImage2
})
})
})
45 changes: 36 additions & 9 deletions packages/core/tests/controllers/ConnectionController.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import { describe, expect, it } from 'vitest'
import type { ConnectionControllerClient } from '../../index.js'
import { ConnectionController } from '../../index.js'
import { describe, expect, it, vi } from 'vitest'
import type { ConnectionControllerClient, ConnectorType } from '../../index.js'
import { ConnectionController, ConstantsUtil, StorageUtil } from '../../index.js'

// -- Setup --------------------------------------------------------------------
const walletConnectUri = 'wc://uri?=123'
const externalId = 'coinbaseWallet'
const type = 'EMAIL'
const type = 'EMAIL' as ConnectorType
const storageSpy = vi.spyOn(StorageUtil, 'setConnectedConnector')

const client: ConnectionControllerClient = {
connectWalletConnect: async onUri => {
onUri(walletConnectUri)
await Promise.resolve()
await Promise.resolve(walletConnectUri)
},
disconnect: async () => Promise.resolve(),
signMessage: async (message: string) => Promise.resolve(message),
connectExternal: async _id => Promise.resolve(),
checkInstalled: _id => true
}

const clientConnectExternalSpy = vi.spyOn(client, 'connectExternal')
const clientCheckInstalledSpy = vi.spyOn(client, 'checkInstalled')

const partialClient: ConnectionControllerClient = {
connectWalletConnect: async () => Promise.resolve(),
disconnect: async () => Promise.resolve(),
Expand Down Expand Up @@ -47,26 +51,49 @@ describe('ConnectionController', () => {
expect(ConnectionController.state.wcPromise).toEqual(undefined)
})

it('should not throw on connectWalletConnect()', () => {
it('should update state correctly and set wcPromise on connectWalletConnect()', async () => {
// Setup timers for pairing expiry
const fakeDate = new Date(0)
vi.useFakeTimers()
vi.setSystemTime(fakeDate)

ConnectionController.connectWalletConnect()
expect(ConnectionController.state.wcPromise).toBeDefined()

// Await on set promise and check results
await ConnectionController.state.wcPromise
expect(ConnectionController.state.wcUri).toEqual(walletConnectUri)
expect(ConnectionController.state.wcPairingExpiry).toEqual(ConstantsUtil.FOUR_MINUTES_MS)
expect(storageSpy).toHaveBeenCalledWith('WALLET_CONNECT')

// Just in case
vi.useRealTimers()
})

it('should not throw on connectExternal()', async () => {
await ConnectionController.connectExternal({ id: externalId, type })
it('connectExternal() should trigger internal client call and set connector in storage', async () => {
const options = { id: externalId, type }
await ConnectionController.connectExternal(options)
expect(storageSpy).toHaveBeenCalledWith(type)
expect(clientConnectExternalSpy).toHaveBeenCalledWith(options)
})

it('should not throw on checkInstalled()', () => {
it('checkInstalled() should trigger internal client call', () => {
ConnectionController.checkInstalled([externalId])
expect(clientCheckInstalledSpy).toHaveBeenCalledWith([externalId])
})

it('should not throw on checkInstalled() without ids', () => {
ConnectionController.checkInstalled()
expect(clientCheckInstalledSpy).toHaveBeenCalledWith(undefined)
})

it('should not throw when optional methods are undefined', async () => {
ConnectionController.setClient(partialClient)
await ConnectionController.connectExternal({ id: externalId, type })
ConnectionController.checkInstalled([externalId])
expect(clientCheckInstalledSpy).toHaveBeenCalledWith([externalId])
expect(clientCheckInstalledSpy).toHaveBeenCalledWith(undefined)
expect(ConnectionController.state._client).toEqual(partialClient)
})

it('should update state correctly on resetWcConnection()', () => {
Expand Down