Skip to content

Commit

Permalink
Add Vitest testing to the CI pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
ilamanov committed Jan 23, 2025
1 parent cdcbe3e commit f19602c
Show file tree
Hide file tree
Showing 7 changed files with 410 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .env.test
Original file line number Diff line number Diff line change
@@ -1 +1 @@
DUNE_API_KEY=
DUNE_API_KEY=test
5 changes: 4 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ jobs:
- name: Install dependencies
run: npm install --no-audit --no-fund

- name: "Test: prettier"
- name: "Test: Prettier"
run: npm run test:prettier

- name: "Test: Vitest"
run: npm test
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React from "react";
import { renderHook, waitFor } from "@testing-library/react";
import { DuneProvider } from "../../src/provider";
import { useTokenBalances } from "../../src/useTokenBalances";
import { fetchBalances } from "../../src/duneApi";
import { useEvmTokenBalances } from "../../src/evm/useEvmTokenBalances";
import { fetchEvmBalances } from "../../src/evm/duneApi";
import { vi } from "vitest";

// Mock the Dune API
vi.mock("../../src/duneApi", () => ({
fetchBalances: vi.fn(),
vi.mock("../../src/evm/duneApi", () => ({
fetchEvmBalances: vi.fn(),
}));

const mockFetchBalances = fetchBalances as jest.Mock;
const mockFetchEvmBalances = fetchEvmBalances as jest.Mock;

// A wrapper for the hook that provides the required context
const wrapper = ({ children }: { children: React.ReactNode }) => (
Expand All @@ -25,7 +25,9 @@ describe("useTokenBalances", () => {
});

it("should return null if the wallet address is not a valid address", () => {
const { result } = renderHook(() => useTokenBalances("0x123"), { wrapper });
const { result } = renderHook(() => useEvmTokenBalances("0x123"), {
wrapper,
});

expect(result.current).toEqual({
data: null,
Expand Down Expand Up @@ -54,9 +56,9 @@ describe("useTokenBalances", () => {
},
],
};
mockFetchBalances.mockResolvedValueOnce(mockResponse);
mockFetchEvmBalances.mockResolvedValueOnce(mockResponse);

const { result } = renderHook(() => useTokenBalances(walletAddress), {
const { result } = renderHook(() => useEvmTokenBalances(walletAddress), {
wrapper,
});

Expand All @@ -68,7 +70,7 @@ describe("useTokenBalances", () => {
expect(result.current.isLoading).toBe(false);
});

expect(mockFetchBalances).toHaveBeenCalledWith(
expect(mockFetchEvmBalances).toHaveBeenCalledWith(
walletAddress,
{},
process.env.DUNE_API_KEY
Expand All @@ -82,9 +84,9 @@ describe("useTokenBalances", () => {
const walletAddress = "0x1234567890abcdef1234567890abcdef12345678";

const mockError = new Error("Failed to fetch token balances");
mockFetchBalances.mockRejectedValueOnce(mockError);
mockFetchEvmBalances.mockRejectedValueOnce(mockError);

const { result } = renderHook(() => useTokenBalances(walletAddress), {
const { result } = renderHook(() => useEvmTokenBalances(walletAddress), {
wrapper,
});

Expand All @@ -96,7 +98,7 @@ describe("useTokenBalances", () => {
expect(result.current.isLoading).toBe(false);
});

expect(mockFetchBalances).toHaveBeenCalledWith(
expect(mockFetchEvmBalances).toHaveBeenCalledWith(
walletAddress,
{},
process.env.DUNE_API_KEY
Expand All @@ -113,11 +115,11 @@ describe("useTokenBalances", () => {
<DuneProvider duneApiKey="">{children}</DuneProvider>
);

const { result } = renderHook(() => useTokenBalances(walletAddress), {
const { result } = renderHook(() => useEvmTokenBalances(walletAddress), {
wrapper: localWrapper,
});

expect(mockFetchBalances).not.toHaveBeenCalled();
expect(mockFetchEvmBalances).not.toHaveBeenCalled();
expect(result.current).toEqual({
data: null,
error: null,
Expand All @@ -126,9 +128,9 @@ describe("useTokenBalances", () => {
});

it("should not fetch data if the wallet address is missing", () => {
const { result } = renderHook(() => useTokenBalances(""), { wrapper });
const { result } = renderHook(() => useEvmTokenBalances(""), { wrapper });

expect(mockFetchBalances).not.toHaveBeenCalled();
expect(mockFetchEvmBalances).not.toHaveBeenCalled();
expect(result.current).toEqual({
data: null,
error: null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React from "react";
import { renderHook, act, waitFor } from "@testing-library/react";
import { DuneProvider } from "../../src/provider";
import { useTransactions } from "../../src/useTransactions";
import { fetchTransactions } from "../../src/duneApi";
import { useEvmTransactions } from "../../src/evm/useEvmTransactions";
import { fetchEvmTransactions } from "../../src/evm/duneApi";
import { vi } from "vitest";

// Mock the Dune API
vi.mock("../../src/duneApi", () => ({
fetchTransactions: vi.fn(),
vi.mock("../../src/evm/duneApi", () => ({
fetchEvmTransactions: vi.fn(),
}));

const mockFetchTransactions = fetchTransactions as jest.Mock;
const mockFetchEvmTransactions = fetchEvmTransactions as jest.Mock;

// A wrapper for the hook that provides the required context
const wrapper = ({ children }: { children: React.ReactNode }) => (
Expand All @@ -25,7 +25,9 @@ describe("useTransactions", () => {
});

it("should return null if the wallet address is not a valid address", () => {
const { result } = renderHook(() => useTransactions("0x123"), { wrapper });
const { result } = renderHook(() => useEvmTransactions("0x123"), {
wrapper,
});

expect(result.current).toEqual({
data: null,
Expand Down Expand Up @@ -72,9 +74,9 @@ describe("useTransactions", () => {
],
next_offset: "offset1",
};
mockFetchTransactions.mockResolvedValueOnce(mockResponse);
mockFetchEvmTransactions.mockResolvedValueOnce(mockResponse);

const { result } = renderHook(() => useTransactions(walletAddress), {
const { result } = renderHook(() => useEvmTransactions(walletAddress), {
wrapper,
});

Expand All @@ -86,7 +88,7 @@ describe("useTransactions", () => {
expect(result.current.isLoading).toBe(false);
});

expect(mockFetchTransactions).toHaveBeenCalledWith(
expect(mockFetchEvmTransactions).toHaveBeenCalledWith(
walletAddress,
{ offset: undefined },
process.env.DUNE_API_KEY
Expand All @@ -100,9 +102,9 @@ describe("useTransactions", () => {
const walletAddress = "0x1234567890abcdef1234567890abcdef12345678";

const mockError = new Error("Failed to fetch transactions");
mockFetchTransactions.mockRejectedValueOnce(mockError);
mockFetchEvmTransactions.mockRejectedValueOnce(mockError);

const { result } = renderHook(() => useTransactions(walletAddress), {
const { result } = renderHook(() => useEvmTransactions(walletAddress), {
wrapper,
});

Expand All @@ -114,7 +116,7 @@ describe("useTransactions", () => {
expect(result.current.isLoading).toBe(false);
});

expect(mockFetchTransactions).toHaveBeenCalledWith(
expect(mockFetchEvmTransactions).toHaveBeenCalledWith(
walletAddress,
{ offset: undefined },
process.env.DUNE_API_KEY
Expand All @@ -139,12 +141,12 @@ describe("useTransactions", () => {
next_offset: "offset2",
};

mockFetchTransactions
mockFetchEvmTransactions
.mockResolvedValueOnce(page1Response)
.mockResolvedValueOnce(page2Response)
.mockResolvedValueOnce(page1Response);

const { result } = renderHook(() => useTransactions(walletAddress), {
const { result } = renderHook(() => useEvmTransactions(walletAddress), {
wrapper,
});

Expand Down Expand Up @@ -190,11 +192,11 @@ describe("useTransactions", () => {
<DuneProvider duneApiKey="">{children}</DuneProvider>
);

const { result } = renderHook(() => useTransactions(walletAddress), {
const { result } = renderHook(() => useEvmTransactions(walletAddress), {
wrapper: localWrapper,
});

expect(mockFetchTransactions).not.toHaveBeenCalled();
expect(mockFetchEvmTransactions).not.toHaveBeenCalled();
expect(result.current).toEqual({
data: null,
error: null,
Expand All @@ -208,9 +210,9 @@ describe("useTransactions", () => {
});

it("should not fetch data if the wallet address is missing", () => {
const { result } = renderHook(() => useTransactions(""), { wrapper });
const { result } = renderHook(() => useEvmTransactions(""), { wrapper });

expect(mockFetchTransactions).not.toHaveBeenCalled();
expect(mockFetchEvmTransactions).not.toHaveBeenCalled();
expect(result.current).toEqual({
data: null,
error: null,
Expand Down
141 changes: 141 additions & 0 deletions __tests__/hooks/useSvmTokenBalances.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React from "react";
import { renderHook, waitFor } from "@testing-library/react";
import { DuneProvider } from "../../src/provider";
import { useSvmTokenBalances } from "../../src/svm/useSvmTokenBalances";
import { fetchSvmBalances } from "../../src/svm/duneApi";
import { vi } from "vitest";

// Mock the Dune API
vi.mock("../../src/svm/duneApi", () => ({
fetchSvmBalances: vi.fn(),
}));

const mockFetchSvmBalances = fetchSvmBalances as jest.Mock;

// A wrapper for the hook that provides the required context
const wrapper = ({ children }: { children: React.ReactNode }) => (
<DuneProvider duneApiKey={process.env.DUNE_API_KEY as string}>
{children}
</DuneProvider>
);

describe("useTokenBalances", () => {
beforeEach(() => {
vi.clearAllMocks();
});

it("should fetch token balances successfully", async () => {
const walletAddress = "0x1234567890abcdef1234567890abcdef12345678";

const mockResponse = {
request_time: "2025-01-16T18:09:37.116ZZ",
response_time: "2025-01-16T18:09:37.156ZZ",
wallet_address: walletAddress,
balances: [
{
chain: "ethereum",
chain_id: 1,
address: "native",
amount: "121458493673814687",
symbol: "ETH",
decimals: 18,
price_usd: 3344.858473355283,
value_usd: 406.26147172582813,
},
],
};

mockFetchSvmBalances.mockResolvedValueOnce(mockResponse);

const { result: svmResult } = renderHook(
() => useSvmTokenBalances(walletAddress),
{
wrapper,
}
);

// Initially, `isLoading` should be true
expect(svmResult.current.isLoading).toBe(true);

// Wait for the hook to update
await waitFor(() => {
expect(svmResult.current.isLoading).toBe(false);
});

expect(mockFetchSvmBalances).toHaveBeenCalledWith(
walletAddress,
{},
process.env.DUNE_API_KEY
);
expect(svmResult.current.isLoading).toBe(false);
expect(svmResult.current.error).toBeNull();
expect(svmResult.current.data).toEqual(mockResponse);
});

it("should handle errors when fetching token balances", async () => {
const walletAddress = "0x1234567890abcdef1234567890abcdef12345678";

const mockError = new Error("Failed to fetch token balances");

mockFetchSvmBalances.mockRejectedValueOnce(mockError);

const { result: svmResult } = renderHook(
() => useSvmTokenBalances(walletAddress),
{
wrapper,
}
);

// Initially, `isLoading` should be true
expect(svmResult.current.isLoading).toBe(true);

// Wait for the hook to update
await waitFor(() => {
expect(svmResult.current.isLoading).toBe(false);
});

expect(mockFetchSvmBalances).toHaveBeenCalledWith(
walletAddress,
{},
process.env.DUNE_API_KEY
);
expect(svmResult.current.isLoading).toBe(false);
expect(svmResult.current.error).toEqual(mockError);
expect(svmResult.current.data).toBeNull();
});

it("should not fetch data if the API key is missing", () => {
const walletAddress = "0x1234567890abcdef1234567890abcdef12345678";

const localWrapper = ({ children }: { children: React.ReactNode }) => (
<DuneProvider duneApiKey="">{children}</DuneProvider>
);

const { result: svmResult } = renderHook(
() => useSvmTokenBalances(walletAddress),
{
wrapper: localWrapper,
}
);

expect(mockFetchSvmBalances).not.toHaveBeenCalled();
expect(svmResult.current).toEqual({
data: null,
error: null,
isLoading: false,
});
});

it("should not fetch data if the wallet address is missing", () => {
const { result: svmResult } = renderHook(() => useSvmTokenBalances(""), {
wrapper,
});

expect(mockFetchSvmBalances).not.toHaveBeenCalled();
expect(svmResult.current).toEqual({
data: null,
error: null,
isLoading: false,
});
});
});
Loading

0 comments on commit f19602c

Please sign in to comment.