Skip to content

Commit

Permalink
Add Vitest testing to the CI pipeline (#13)
Browse files Browse the repository at this point in the history
Also updates the test files which were failing due to recent rename to EVM files.
Adds SVM tests as well
  • Loading branch information
ilamanov authored Jan 23, 2025
2 parents cdcbe3e + f19602c commit 6847152
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 6847152

Please sign in to comment.