Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
* set resetMocks to false for jest config
* mock interchain-ui styles, @cosmos-kit/react, wagmi
* remove providers from `renderWithRouter`
* remove duplicated mocks
  • Loading branch information
steezeburger committed Dec 7, 2024
1 parent 911dd72 commit cc937d6
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 139 deletions.
3 changes: 3 additions & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
"typescript": "^5"
}
},
"jest": {
"resetMocks": false
},
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
Expand Down
7 changes: 0 additions & 7 deletions web/src/pages/BridgePage/BridgePage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@ import { screen } from "@testing-library/react";
import { renderWithRouter } from "testHelpers";
import BridgePage from "./BridgePage";

// mock useNavigate
const mockNavigate = jest.fn();
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"), // preserve other exports
useNavigate: () => mockNavigate,
}));

describe("BridgePage", () => {
test("renders bridge page correctly", () => {
renderWithRouter(<BridgePage />);
Expand Down
154 changes: 75 additions & 79 deletions web/src/setupTests.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,3 @@
// mock @interchain-ui/react's core functionality for cosmos-kit
jest.mock('@interchain-ui/react', () => ({
// biome-ignore lint/suspicious/noExplicitAny: idc b/c it's for testing
ThemeProvider: ({ children }: { children: any }) => children,
useTheme: () => ({
themeMode: 'dark',
setThemeMode: jest.fn()
}),
}));

// mock styles used by cosmos-kit
jest.mock('@interchain-ui/react/styles', () => ({}), { virtual: true });

// mock window.matchMedia for cosmos-kit's theming code
Object.defineProperty(window, 'matchMedia', {
configurable: true,
value: jest.fn(() => ({
matches: false,
media: "(prefers-color-scheme: light)",
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
}))
});

// TODO - mock WalletModal from cosmos-kit

// TODO - bring this mock back and remove providers in testHelpers.tsx
// And ensure wagmi mock is complete
// jest.mock('wagmi', () => {
// return {
// WagmiProvider: jest.fn(({ children }) => children),
// createConfig: jest.fn(() => ({
// chains: [],
// client: {},
// })),
// createConnector: jest.fn(),
// http: jest.fn(),
// useAccount: jest.fn(() => ({
// address: '0x0',
// isConnected: false,
// isConnecting: false,
// isDisconnected: true,
// })),
// useConnect: jest.fn(() => ({
// connect: jest.fn(),
// connectors: [],
// })),
// useDisconnect: jest.fn(() => ({
// disconnect: jest.fn(),
// })),
// useBalance: jest.fn(() => ({
// data: { formatted: '0', symbol: 'ETH' },
// })),
// useNetwork: jest.fn(() => ({
// chain: null,
// chains: [],
// })),
// useConfig: jest.fn(() => ({
// config: {
// chains: [],
// },
// })),
// };
// });


// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
Expand All @@ -76,22 +6,88 @@ import "@testing-library/jest-dom";

import { TextDecoder, TextEncoder } from "node:util";

// mocked useNavigate so we can use web api in tests which run in node
const mockedUseNavigate = jest.fn();
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useNavigate: () => mockedUseNavigate,
}));

// silence console logs and warnings
jest.spyOn(console, "debug").mockImplementation(() => {});
// jest.spyOn(console, "log").mockImplementation(() => {});
jest.spyOn(console, "log").mockImplementation(() => {});
jest.spyOn(console, "warn").mockImplementation(() => {});
jest.spyOn(console, "error").mockImplementation(() => {});

// mocked useNavigate so we can use web api in tests which run in node
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useNavigate: () => jest.fn(),
}));

// mock browser globals
Object.defineProperties(global, {
TextDecoder: { value: TextDecoder },
TextEncoder: { value: TextEncoder },
});

global.setImmediate = jest.useRealTimers as unknown as typeof setImmediate;

// mock styles used by cosmos-kit
jest.mock("@interchain-ui/react/styles", () => ({}), { virtual: true });

// mock cosmos-kit stuff
jest.mock("@cosmos-kit/react", () => ({
// biome-ignore lint/suspicious/noExplicitAny: idc b/c it's for testing
ChainProvider: jest.fn(({ children }: { children: any }) => children),
useWalletModal: jest.fn(() => ({
openWalletModal: jest.fn(),
closeWalletModal: jest.fn(),
})),
WalletModal: jest.fn(() => <div>Mocked WalletModal Component</div>),
useChain: jest.fn(() => ({
openView: jest.fn(),
address: "0xb0E31D878F49Ec0403A25944d6B1aE1bf05D17E1",
})),
}));

// mock wagmi completely
jest.mock("wagmi", () => {
return {
WagmiProvider: jest.fn(({ children }) => children),
createConfig: jest.fn(() => ({
chains: [],
client: {},
})),
createConnector: jest.fn(),
http: jest.fn(),
useAccount: jest.fn(() => ({
address: "0xb0E31D878F49Ec0403A25944d6B1aE1bf05D17E1",
isConnected: true,
isConnecting: false,
isDisconnected: false,
})),
useAccountEffect: jest.fn(),
useConnect: jest.fn(() => ({
connect: jest.fn(),
connectAsync: jest.fn(() => Promise.resolve()),
connectors: [],
})),
useDisconnect: jest.fn(() => ({
disconnect: jest.fn(),
})),
useBalance: jest.fn(() => ({
data: { formatted: "0", symbol: "ETH" },
})),
useNetwork: jest.fn(() => ({
chain: null,
chains: [],
})),
useConfig: jest.fn(() => ({
chains: ["celestia"],
})),
usePublicClient: jest.fn(),
useEnsName: jest.fn(() => ({
data: {},
})),
useEnsAvatar: jest.fn(() => ({
data: {},
})),
useSwitchChain: jest.fn(() => ({
chains: [],
switchChain: jest.fn(),
})),
};
});
57 changes: 4 additions & 53 deletions web/src/testHelpers.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,15 @@
import { MemoryRouter, Route, Routes } from "react-router-dom";
import { render } from "@testing-library/react";
import type React from "react";
import {
ConfigContextProvider,
type EvmChains,
evmChainsToRainbowKitChains,
} from "config";
import { getDefaultConfig, RainbowKitProvider } from "@rainbow-me/rainbowkit";
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { assets } from "chain-registry";
import { wallets } from "@cosmos-kit/keplr";
import { ChainProvider } from "@cosmos-kit/react";

const evmChains: EvmChains = {
Testchain: {
chainId: 1337,
chainName: "Testchain",
currencies: [
{
coinDenom: "Testchain",
coinMinimalDenom: "testchain",
coinDecimals: 18,
ibcWithdrawalFeeWei: "0",
},
],
rpcUrls: ["http://localhost:8545"],
blockExplorerUrl: "https://testchain-explorer.com",
},
};

const rainbowKitConfig = getDefaultConfig({
appName: "Flame Bridge",
projectId: "YOUR_PROJECT_ID", // TODO
chains: evmChainsToRainbowKitChains(evmChains),
});

const queryClient = new QueryClient();
import { ConfigContextProvider } from "config";

export const renderWithRouter = (element: React.JSX.Element) => {
render(
<MemoryRouter>
<ConfigContextProvider>
{/* TODO - mock WagmiProvider, RainbowKitProvider, ChainProvider b/c App is wrapped with them. */}
<WagmiProvider config={rainbowKitConfig}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider>
<ChainProvider
walletModal={(props) => <div>WalletModal</div>}
chains={["celestia"]} // supported chains
assetLists={assets} // supported asset lists
wallets={wallets} // supported wallets
>
<Routes>
<Route index path={"*"} element={element} />
</Routes>
</ChainProvider>
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
<Routes>
<Route index path={"*"} element={element} />
</Routes>
</ConfigContextProvider>
</MemoryRouter>,
);
Expand Down

0 comments on commit cc937d6

Please sign in to comment.