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

Add mobile drawer and useBreakpoints hook #1045

Merged
merged 21 commits into from
Aug 15, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add test coverage
alissacrane-cb committed Aug 15, 2024

Unverified

This user has not yet uploaded their public signing key.
commit cd54cf7a0b4cf841590829789cd8aa7301f0b64a
104 changes: 104 additions & 0 deletions src/wallet/components/WalletBottomSheet.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import '@testing-library/jest-dom';
import {
fireEvent,
render,
renderHook,
screen,
waitFor,
} from '@testing-library/react';
import { useAccount } from 'wagmi';
import { Identity } from '../../identity/components/Identity';
import {
IdentityProvider,
useIdentityContext,
} from '../../identity/components/IdentityProvider';
import { WalletBottomSheet } from './WalletBottomSheet';
import { useWalletContext } from './WalletProvider';

vi.mock('wagmi', () => ({
useAccount: vi.fn(),
}));

vi.mock('./WalletProvider', () => ({
useWalletContext: vi.fn(),
}));

vi.mock('../../identity/components/Identity', () => ({
Identity: vi.fn(({ address, children }) => (
<IdentityProvider address={address}>{children}</IdentityProvider>
)),
}));

const useWalletContextMock = useWalletContext as vi.Mock;
const useAccountMock = useAccount as vi.Mock;

describe('WalletBottomSheet', () => {
it('renders null when address is not provided', () => {
useWalletContextMock.mockReturnValue({ isOpen: true });
useAccountMock.mockReturnValue({ address: null });

render(<WalletBottomSheet>Test Children</WalletBottomSheet>);

expect(screen.queryByText('Test Children')).not.toBeInTheDocument();
});

it('renders children when isOpen is true and address is provided', () => {
useWalletContextMock.mockReturnValue({ isOpen: true });
useAccountMock.mockReturnValue({ address: '0x123' });

render(<WalletBottomSheet>Test Children</WalletBottomSheet>);

expect(screen.getByText('Test Children')).toBeInTheDocument();
});

it('injects address prop to Identity component', async () => {
const address = '0x123';
useWalletContextMock.mockReturnValue({ isOpen: true });
useAccountMock.mockReturnValue({ address });

const { result } = renderHook(() => useIdentityContext(), {
wrapper: ({ children }) => (
<WalletBottomSheet>
<Identity>{children}</Identity>
</WalletBottomSheet>
),
});

await waitFor(() => {
expect(result.current.address).toEqual(address);
});
});

it('does not render overlay when isOpen is false', () => {
useAccountMock.mockReturnValue({ address: '0x123' });
useWalletContextMock.mockReturnValue({ isOpen: false, setIsOpen: vi.fn() });

render(<WalletBottomSheet>Content</WalletBottomSheet>);

expect(screen.queryByRole('button')).not.toBeInTheDocument();
});

it('renders overlay when isOpen is true', () => {
useAccountMock.mockReturnValue({ address: '0x123' });
useWalletContextMock.mockReturnValue({ isOpen: true, setIsOpen: vi.fn() });

render(<WalletBottomSheet>Content</WalletBottomSheet>);

expect(screen.getByRole('button')).toBeInTheDocument();
});

it('closes the bottom sheet when the overlay is clicked', () => {
const setIsOpenMock = vi.fn();
useAccountMock.mockReturnValue({ address: '0x123' });
useWalletContextMock.mockReturnValue({
isOpen: true,
setIsOpen: setIsOpenMock,
});

render(<WalletBottomSheet>Content</WalletBottomSheet>);

fireEvent.click(screen.getByRole('button'));

expect(setIsOpenMock).toHaveBeenCalledWith(false);
});
});
1 change: 1 addition & 0 deletions src/wallet/components/WalletBottomSheet.tsx
Original file line number Diff line number Diff line change
@@ -64,6 +64,7 @@ export function WalletBottomSheet({
`${isOpen ? 'translate-y-0' : 'translate-y-full'}`,
className,
)}
data-testid="ockWalletBottomSheet"
>
{childrenArray}
</div>
1 change: 1 addition & 0 deletions src/wallet/components/WalletDropdown.tsx
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ export function WalletDropdown({ children, className }: WalletDropdownReact) {
'absolute right-0 z-10 mt-1 flex w-max min-w-[250px] flex-col overflow-hidden rounded-xl pb-2',
className,
)}
data-testid="ockWalletDropdown"
>
{childrenArray}
</div>
63 changes: 63 additions & 0 deletions src/wallet/components/WalletMenu.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import { useAccount } from 'wagmi';
import { WalletMenu } from './WalletMenu';
import useBreakpoints from '../../useBreakpoints';

vi.mock('wagmi', () => ({
useAccount: vi.fn(),
}));

vi.mock('../../useBreakpoints', () => ({
default: vi.fn(),
}));

const useAccountMock = useAccount as vi.Mock;
const useBreakpointsMock = useBreakpoints as vi.Mock;

describe('WalletMenu', () => {
beforeEach(() => {
vi.clearAllMocks();
});

it('does not render anything if address is not available', () => {
useAccountMock.mockReturnValue({ address: null });
useBreakpointsMock.mockReturnValue('sm');

render(<WalletMenu>Content</WalletMenu>);

expect(screen.queryByText('Content')).not.toBeInTheDocument();
});

it('does not render anything if breakpoint is not defined', () => {
useAccountMock.mockReturnValue({ address: '0x123' });
useBreakpointsMock.mockReturnValue(null);

render(<WalletMenu>Content</WalletMenu>);

expect(screen.queryByText('Content')).not.toBeInTheDocument();
});

it('renders WalletBottomSheet when breakpoint is "sm"', () => {
useAccountMock.mockReturnValue({ address: '0x123' });
useBreakpointsMock.mockReturnValue('sm');

render(<WalletMenu className="bottom-sheet">Content</WalletMenu>);

const bottomSheet = screen.getByTestId('ockWalletBottomSheet');
expect(bottomSheet).toBeInTheDocument();
expect(bottomSheet).toHaveClass('bottom-sheet');
});

it('renders WalletDropdown when breakpoint is not "sm"', () => {
useAccountMock.mockReturnValue({ address: '0x123' });
useBreakpointsMock.mockReturnValue('md');

render(<WalletMenu className="dropdown">Content</WalletMenu>);

const dropdown = screen.getByTestId('ockWalletDropdown');

expect(dropdown).toBeInTheDocument();
expect(dropdown).toHaveClass('dropdown');
});
});
138 changes: 138 additions & 0 deletions src/wallet/components/WalletWithMobileDrawer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ConnectWallet } from './ConnectWallet';
import { WalletWithMobileDrawer } from './WalletWithMobileDrawer';
import { WalletMenu } from './WalletMenu';
import { useWalletContext } from './WalletProvider';
import { useAccount } from 'wagmi';
import useBreakpoints from '../../useBreakpoints';

vi.mock('./WalletProvider', () => ({
useWalletContext: vi.fn(),
WalletProvider: ({ children }) => <>{children}</>,
}));

vi.mock('./ConnectWallet', () => ({
ConnectWallet: () => <div data-testid="connect-wallet">Connect Wallet</div>,
}));

vi.mock('./WalletDropdown', () => ({
WalletDropdown: () => (
<div data-testid="wallet-dropdown">Wallet Dropdown</div>
),
}));

vi.mock('wagmi', () => ({
useAccount: vi.fn(),
}));

vi.mock('../../useBreakpoints', () => ({
default: vi.fn(),
}));

const useAccountMock = useAccount as vi.Mock;
const useBreakpointsMock = useBreakpoints as vi.Mock;

describe('WalletWithMobileDrawer Component', () => {
let mockSetIsOpen: ReturnType<typeof vi.fn>;

beforeEach(() => {
mockSetIsOpen = vi.fn();
(useWalletContext as ReturnType<typeof vi.fn>).mockReturnValue({
isOpen: false,
setIsOpen: mockSetIsOpen,
});
});

it('should render the Wallet component with ConnectWallet', () => {
render(
<WalletWithMobileDrawer>
<ConnectWallet />
<WalletMenu />
</WalletWithMobileDrawer>,
);

expect(screen.getByTestId('connect-wallet')).toBeDefined();
expect(screen.queryByTestId('wallet-dropdown')).toBeNull();
});

it('should close the wallet when clicking outside', () => {
(useWalletContext as ReturnType<typeof vi.fn>).mockReturnValue({
isOpen: true,
setIsOpen: mockSetIsOpen,
});

useAccountMock.mockReturnValue({ address: '123' });
useBreakpointsMock.mockReturnValue('sm');

render(
<WalletWithMobileDrawer>
<ConnectWallet />
<WalletMenu />
</WalletWithMobileDrawer>,
);

expect(screen.getByTestId('ockWalletBottomSheet')).toBeDefined();

fireEvent.click(document.body);

expect(mockSetIsOpen).toHaveBeenCalledWith(false);
});

it('should not close the wallet when clicking inside', () => {
(useWalletContext as ReturnType<typeof vi.fn>).mockReturnValue({
isOpen: true,
setIsOpen: mockSetIsOpen,
});

useAccountMock.mockReturnValue({ address: '123' });
useBreakpointsMock.mockReturnValue('sm');

render(
<WalletWithMobileDrawer>
<ConnectWallet />
<WalletMenu />
</WalletWithMobileDrawer>,
);

const walletMenu = screen.getByTestId('ockWalletBottomSheet');
expect(walletMenu).toBeDefined();

fireEvent.click(walletMenu);

expect(mockSetIsOpen).not.toHaveBeenCalled();
});

it('should not trigger click handler when wallet is closed', () => {
render(
<WalletWithMobileDrawer>
<ConnectWallet />
<WalletMenu />
</WalletWithMobileDrawer>,
);

expect(screen.queryByTestId('wallet-dropdown')).toBeNull();

fireEvent.click(document.body);

expect(mockSetIsOpen).not.toHaveBeenCalled();
});

it('should remove event listener on unmount', () => {
const removeEventListenerSpy = vi.spyOn(document, 'removeEventListener');

const { unmount } = render(
<WalletWithMobileDrawer>
<ConnectWallet />
<WalletMenu />
</WalletWithMobileDrawer>,
);

unmount();

expect(removeEventListenerSpy).toHaveBeenCalledWith(
'click',
expect.any(Function),
);
});
});