Skip to content

Commit

Permalink
chore: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
slavastartsev committed Dec 2, 2024
1 parent d6912b6 commit e852204
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,76 +4,167 @@ import { Token } from '@gobob/currency';
import { renderHook } from '@testing-library/react-hooks';
import { PropsWithChildren } from 'react';
import { Address } from 'viem';
import { describe, expect, it, Mock, vi } from 'vitest';

vi.mock('@/lib/bob-sdk', () => ({
gatewaySDK: {
getStrategies: vi.fn()
}
}));

vi.mock('@/hooks/useFeatureFlag', () => ({
FeatureFlags: { BTC_GATEWAY: vi.fn() },
useFeatureFlag: vi.fn()
}));
import { useReadContracts } from 'wagmi';
import { afterEach, beforeEach, describe, expect, it, Mock, vi } from 'vitest';
import { usePrices } from '@gobob/hooks';
import Big from 'big.js';

import { useGetStakingStrategies } from '../useGetStakingStrategies';

import { wrapper } from '@/test-utils';
import { useFeatureFlag } from '@/hooks';
import { gatewaySDK } from '@/lib/bob-sdk';
import { wrapper } from '@/test-utils';

vi.mock(import('@/lib/bob-sdk'), async (importOriginal) => {
const actual = await importOriginal();

actual.gatewaySDK.getStrategies = vi.fn();

return actual;
});

vi.mock(import('wagmi'), async (importOriginal) => {
const actual = await importOriginal();

return {
...actual,
useReadContracts: vi.fn()
};
});

vi.mock(import('@gobob/hooks'), async (importOriginal) => {
const actual = await importOriginal();

return {
...actual,
usePrices: vi.fn()
};
});

const mockStrategy: GatewayStrategyContract = {
id: 'testnet-strategy',
id: 'bedrock-unibtc',
type: 'deposit',
address: '0x06cea150e651236499319d78f92791f0fae6fe67',
address: '0x98649858a2d008410cb3bc6533fc2571905c456d',
method: '',
chain: {
id: '',
chainId: 808813,
slug: 'bob-sepolia',
name: 'bob-sepolia',
chainId: 60808,
slug: 'bob',
name: 'bob',
logo: '',
type: 'evm',
singleChainSwap: true,
singleChainStaking: true
},
integration: {
type: 'staking',
slug: 'testnet-strategy',
name: 'Testnet Strategy',
logo: 'https://ethereum-optimism.github.io/data/tBTC/logo.svg',
slug: 'bedrock-unibtc',
name: 'Bedrock (uniBTC)',
logo: 'https://raw.githubusercontent.com/bob-collective/bob/master/assets/uniBTC.svg',
monetization: false
},
inputToken: {
symbol: 'WBTC',
address: '0x03c7054bcb39f7b2e5b2c7acb37583e32d70cfa3',
logo: 'https://ethereum-optimism.github.io/data/WBTC/logo.svg',
decimals: 8,
chain: 'bob'
},
outputToken: {
symbol: 'uniBTC',
address: '0x236f8c0a61da474db21b693fb2ea7aab0c803894',
logo: 'https://raw.githubusercontent.com/bob-collective/bob/master/assets/uniBTC.svg',
decimals: 8,
chain: 'bob'
}
} as const;

const mockSegmentStrategy: GatewayStrategyContract = {
id: 'segment-tbtc',
type: 'deposit',
address: '0xc8debccfca009f586263d1f1596504b104b22fd2',
method: '',
chain: {
id: '',
chainId: 60808,
slug: 'bob',
name: 'bob',
logo: '',
type: 'evm',
singleChainSwap: true,
singleChainStaking: true
},
integration: {
type: 'lending',
slug: 'segment-tbtc',
name: 'Segment (tBTC)',
logo: 'https://raw.githubusercontent.com/bob-collective/bob/master/assets/segment.svg',
monetization: false
},
inputToken: {
symbol: 'tBTC',
address: '0x6744bAbDf02DCF578EA173A9F0637771A9e1c4d0',
address: '0xbba2ef945d523c4e2608c9e1214c2cc64d4fc2e2',
logo: 'https://ethereum-optimism.github.io/data/tBTC/logo.svg',
decimals: 18,
chain: 'bob-sepolia'
chain: 'bob'
},
outputToken: {
symbol: 'stmtBTC',
address: '0xc4229678b65e2d9384fdf96f2e5d512d6eec0c77',
logo: 'https://ethereum-optimism.github.io/data/tBTC/logo.svg',
decimals: 18,
chain: 'bob-sepolia'
symbol: 'seTBTC',
address: '0xd30288ea9873f376016a0250433b7ea375676077',
logo: 'https://raw.githubusercontent.com/bob-collective/bob/master/assets/segment.svg',
decimals: 8,
chain: 'bob'
}
};
} as const;

describe('useGetStakingStrategies', () => {
beforeEach(vi.clearAllMocks);
afterEach(vi.clearAllMocks);

const mockExchangeRateStored = 207520794671396869399540716n;
const mockTotalSupply = 9036849246n;
const mockUnderlying = '0xabc';

const underlyingDecimals = 18;
const decimals = 8;

const mockPrice = 91000;

beforeEach(() => {
(useReadContracts as Mock)
.mockReturnValueOnce({
data: [mockExchangeRateStored, mockTotalSupply, mockUnderlying]
})
.mockReturnValueOnce({
data: [underlyingDecimals]
})
.mockReturnValueOnce({
data: [mockTotalSupply, decimals]
});

(usePrices as Mock).mockReturnValue({
getPrice: () => mockPrice
});
});

it('should return strategy data', async () => {
(useReadContracts as Mock)
.mockReturnValueOnce({
data: [mockExchangeRateStored, mockTotalSupply, mockUnderlying]
})
.mockReturnValueOnce({
data: [underlyingDecimals]
})
.mockReturnValueOnce({
data: [mockTotalSupply, decimals]
});

it('should return strategies with Token', async () => {
(useFeatureFlag as Mock).mockReturnValue(true);
(gatewaySDK.getStrategies as Mock).mockReturnValue([mockStrategy]);

const { result, waitFor } = renderHook<PropsWithChildren, ReturnType<typeof useGetStakingStrategies>>(
const { result, waitForValueToChange } = renderHook<PropsWithChildren, ReturnType<typeof useGetStakingStrategies>>(
() => useGetStakingStrategies(),
{ wrapper }
);

await waitFor(() => result.current.isSuccess);
await waitForValueToChange(() => result.current.data);

const expectedData = {
raw: mockStrategy,
Expand All @@ -85,31 +176,88 @@ describe('useGetStakingStrategies', () => {
mockStrategy.outputToken.symbol,
mockStrategy.outputToken.symbol
)
: undefined
: undefined,
tvl: new Big(mockTotalSupply.toString())
.mul(mockPrice)
.div(10 ** decimals)
.toNumber()
};

expect(gatewaySDK.getStrategies).toBeCalledTimes(1);
expect(result.current.data).toEqual([expectedData]);
});

it('should return undefined currency when outputToken is missing', async () => {
(useReadContracts as Mock)
.mockReturnValueOnce({
data: [mockExchangeRateStored, mockTotalSupply, mockUnderlying]
})
.mockReturnValueOnce({
data: [underlyingDecimals]
})
.mockReturnValueOnce({
data: [mockTotalSupply, decimals]
});

const mockStrategyWithoutToken = {
outputToken: undefined
};

(useFeatureFlag as Mock).mockReturnValue(true);
(gatewaySDK.getStrategies as Mock).mockReturnValue([mockStrategyWithoutToken]);

const { result, waitFor } = renderHook<PropsWithChildren, ReturnType<typeof useGetStakingStrategies>>(
const { result, waitForValueToChange } = renderHook<PropsWithChildren, ReturnType<typeof useGetStakingStrategies>>(
() => useGetStakingStrategies(),
{ wrapper }
);

await waitFor(() => result.current.isSuccess);
await waitForValueToChange(() => result.current.data);

const expectedData = {
raw: mockStrategyWithoutToken,
currency: undefined
currency: undefined,
tvl: null
};

expect(result.current.data).toEqual([expectedData]);
});

it('should return tvl value if output token is se* token', async () => {
(useReadContracts as Mock)
.mockReturnValueOnce({
data: [mockExchangeRateStored, mockTotalSupply, mockUnderlying]
})
.mockReturnValueOnce({
data: [underlyingDecimals]
})
.mockReturnValueOnce({
data: [mockTotalSupply, decimals]
});

(gatewaySDK.getStrategies as Mock).mockReturnValue([mockSegmentStrategy]);

const { result, waitForValueToChange } = renderHook<PropsWithChildren, ReturnType<typeof useGetStakingStrategies>>(
() => useGetStakingStrategies(),
{ wrapper }
);

await waitForValueToChange(() => result.current.data);

const expectedData = {
raw: mockSegmentStrategy,
currency: mockSegmentStrategy.outputToken
? new Token(
ChainId.BOB,
mockSegmentStrategy.outputToken.address as Address,
mockSegmentStrategy.outputToken.decimals,
mockSegmentStrategy.outputToken.symbol,
mockSegmentStrategy.outputToken.symbol
)
: undefined,
tvl: new Big((mockExchangeRateStored * mockTotalSupply).toString())
.mul(mockPrice)
.div(1e18)
.div(10 ** underlyingDecimals)
.toNumber()
};

expect(result.current.data).toEqual([expectedData]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,7 @@ const useGetStakingStrategies = () => {
[]
);

const {
data: strategies,
isLoading: isStrategiesLoading,
...rest
} = useGetStrategies({
const { data: strategies, isSuccess: isStrategiesSucess } = useGetStrategies({
select: selectStrategyData
});

Expand All @@ -73,7 +69,7 @@ const useGetStakingStrategies = () => {
(bigint | number)[]
>({
query: {
enabled: !isStrategiesLoading
enabled: isStrategiesSucess
},
allowFailure: false,
contracts: strategies?.flatMap((strategy) =>
Expand Down Expand Up @@ -125,7 +121,7 @@ const useGetStakingStrategies = () => {
number[]
>({
query: {
enabled: Boolean(seTokenContractDataCalls)
enabled: isStrategiesSucess
},
allowFailure: false,
contracts: strategies?.flatMap((strategy) =>
Expand Down Expand Up @@ -166,7 +162,7 @@ const useGetStakingStrategies = () => {
(bigint | number)[]
>({
query: {
enabled: !isStrategiesLoading
enabled: isStrategiesSucess
},
allowFailure: false,
contracts: strategies?.flatMap((strategy) =>
Expand Down Expand Up @@ -258,7 +254,7 @@ const useGetStakingStrategies = () => {
[strategies, seTokenContractDataCalls, seTokenUnderlyingContractDataCalls, tokensContractDataCalls, getPrice]
);

return { ...rest, data: strategiesData, isLoading: isStrategiesLoading };
return { data: strategiesData };
};

export { useGetStakingStrategies };
Expand Down

0 comments on commit e852204

Please sign in to comment.