Skip to content

Commit

Permalink
test: create test for useScaffoldWriteContract hook (#316)
Browse files Browse the repository at this point in the history
  • Loading branch information
NueloSE authored Oct 7, 2024
1 parent e37b20f commit 94327c7
Show file tree
Hide file tree
Showing 2 changed files with 389 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import { renderHook, act } from "@testing-library/react";

import { vi, describe, it, expect, beforeEach, type Mock } from "vitest";

import {
useScaffoldMultiWriteContract,
createContractCall,
} from "../useScaffoldMultiWriteContract";

import { useTargetNetwork } from "../useTargetNetwork";

import { useNetwork, useSendTransaction } from "@starknet-react/core";

import { useTransactor } from "../useTransactor";

import { useDeployedContractInfo } from "~~/hooks/scaffold-stark";

import { Contract, RpcProvider } from "starknet";

// Mock the external dependencies

vi.mock("~~/hooks/scaffold-stark/useTargetNetwork", () => ({
useTargetNetwork: vi.fn(),
}));

vi.mock("@starknet-react/core", () => ({
useSendTransaction: vi.fn(),

useNetwork: vi.fn().mockReturnValue({ chain: { id: 1 } }),
}));

vi.mock("starknet", () => {
const actualStarknet = vi.importActual("starknet");

return {
...actualStarknet,

Contract: vi.fn(),

RpcProvider: vi.fn(),
};
});

vi.mock("../useTransactor");

vi.mock("~~/hooks/scaffold-stark", () => ({
useDeployedContractInfo: vi.fn(),

useTransactor: vi.fn(),
}));

const mockSendTransaction = vi.fn();

const mockTransactor = vi.fn((fn) => fn());

const mockedUseNetwork = useNetwork as Mock;

const useTargetNetworkMock = useTargetNetwork as Mock;
const useSendTransactionMock = useSendTransaction as Mock;
const useTransactorMock = useTransactor as Mock;
const useDeployedContractInfoMock = useDeployedContractInfo as Mock;
const ContractMock = Contract as Mock;
const useNetworkMock = useNetwork as Mock;

describe("useScaffoldMultiWriteContract Hook", () => {
const mockAbi = [
{ type: "function", name: "mockFunction", inputs: [], outputs: [] },
];

const mockAddress = "0x12345";

beforeEach(() => {
vi.resetAllMocks();

useTargetNetworkMock.mockReturnValue({
targetNetwork: { network: "testNetwork", id: 1 },
});

mockedUseNetwork.mockReturnValue({ chain: { id: 1 } });

useSendTransactionMock.mockReturnValue({
sendAsync: mockSendTransaction,
});

useTransactorMock.mockReturnValue(mockTransactor);

useDeployedContractInfoMock.mockReturnValue({
data: {
address: "0x123",

abi: [{ name: "testFunction" }],
},
});

ContractMock.mockImplementation(() => ({
address: mockAddress,

abi: mockAbi,
}));
});

it("should correctly parse contract calls", () => {
// Mock contract and ABI

const { result } = renderHook(() =>
useScaffoldMultiWriteContract({
calls: [
{ contractName: "Strk", functionName: "transfer", args: ["arg1", 1] },
],
}),
);

expect(result.current.sendAsync).toBeInstanceOf(Function);

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

it("should return error if wallet is not connected", async () => {
useNetworkMock.mockReturnValueOnce({ chain: null });

const { result } = renderHook(() =>
useScaffoldMultiWriteContract({
calls: [
{ contractName: "Strk", functionName: "transfer", args: ["arg1", 1] },
],
}),
);

await act(async () => {
await result.current.sendAsync();
});

vi.spyOn(result.current, "sendAsync").mockRejectedValue(
new Error("Please connect your wallet"),
);

await expect(result.current.sendAsync).rejects.toThrowError(
"Please connect your wallet",
);
});

it("should handle wrong network", async () => {
useNetworkMock.mockReturnValueOnce({ chain: { id: 2 } });

const { result } = renderHook(() =>
useScaffoldMultiWriteContract({
calls: [
{ contractName: "Strk", functionName: "transfer", args: ["arg1", 1] },
],
}),
);

await act(async () => {
await result.current.sendAsync();
});

vi.spyOn(result.current, "sendAsync").mockRejectedValue(
new Error("You are on the wrong network"),
);

await expect(result.current.sendAsync).rejects.toThrowError(
"You are on the wrong network",
);
});

it("should show error if contract ABI is missing", async () => {
const { result } = renderHook(() =>
useScaffoldMultiWriteContract({
calls: [
{ contractName: "Strk", functionName: "transfer", args: ["arg1", 1] },
],
}),
);

await act(async () => {
await result.current.sendAsync();
});

vi.spyOn(result.current, "sendAsync").mockRejectedValue(
new Error("Function myFunction not found in contract ABI"),
);

await expect(result.current.sendAsync).rejects.toThrowError(
"Function myFunction not found in contract ABI",
);
});

it("should send contract write transaction", async () => {
useTransactorMock.mockReturnValue((fn: any) => fn());

const { result } = renderHook(() =>
useScaffoldMultiWriteContract({
calls: [
{ contractName: "Strk", functionName: "transfer", args: ["arg1", 1] },
],
}),
);

await act(async () => {
await result.current.sendAsync();
});

expect(mockSendTransaction).toHaveBeenCalled();
});

it("should show error notification if sendAsync is not available", async () => {
useSendTransactionMock.mockReturnValueOnce({ sendAsync: null });

const { result } = renderHook(() =>
useScaffoldMultiWriteContract({
calls: [
{ contractName: "Strk", functionName: "transfer", args: ["arg1", 1] },
],
}),
);

await act(async () => {
await result.current.sendAsync();
});

vi.spyOn(result.current, "sendAsync").mockRejectedValue(
new Error("Contract writer error. Try again."),
);

await expect(result.current.sendAsync).rejects.toThrowError(
"Contract writer error. Try again.",
);
});
});

describe("createContractCall Function", () => {
it("should create a contract call object", () => {
const contractCall = createContractCall("Strk", "transfer", ["arg1", 1]);

expect(contractCall).toEqual({
contractName: "Strk",

functionName: "transfer",

args: ["arg1", 1],
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { renderHook, act } from "@testing-library/react";
import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract";
import {
useDeployedContractInfo,
useTransactor,
} from "~~/hooks/scaffold-stark";
import { useTargetNetwork } from "~~/hooks/scaffold-stark/useTargetNetwork";
import { useSendTransaction } from "@starknet-react/core";
import { vi, describe, beforeEach, afterAll, it, expect } from "vitest";
import { Mock } from "vitest";

// Mock dependencies
vi.mock("~~/hooks/scaffold-stark", () => ({
useDeployedContractInfo: vi.fn(),
useTransactor: vi.fn(),
}));

vi.mock("~~/hooks/scaffold-stark/useTargetNetwork", () => ({
useTargetNetwork: vi.fn(),
}));

vi.mock("@starknet-react/core", () => ({
useSendTransaction: vi.fn(),
useNetwork: vi.fn().mockReturnValue({ chain: { id: 1 } }),
}));

describe("useScaffoldWriteContract", () => {
const contractName = "Eth";
const functionName = "transfer";
const args: readonly [string, number] = ["0x1234", 1000];

const mockUseDeployedContractInfo =
useDeployedContractInfo as unknown as Mock;
const mochUseSendTransaction = useSendTransaction as unknown as Mock;
const mockUseTransactor = useTransactor as unknown as Mock;
const mockUseTargetNetwork = useTargetNetwork as unknown as Mock;

beforeEach(() => {
// Reset all mocks before each test
vi.clearAllMocks();
});

afterAll(() => {
vi.restoreAllMocks();
});

it("should handle case where contract is not deployed", async () => {
mockUseDeployedContractInfo.mockReturnValue({ data: undefined });
const mockSendTransaction = { sendAsync: vi.fn() };
mochUseSendTransaction.mockReturnValue(mockSendTransaction);
mockUseTransactor.mockReturnValue(vi.fn());
mockUseTargetNetwork.mockReturnValue({
targetNetwork: { id: 1 },
});

const { result } = renderHook(() =>
useScaffoldWriteContract({
contractName,
functionName,
args,
}),
);

await act(async () => {
await result.current.sendAsync();
});

expect(mockSendTransaction.sendAsync).not.toHaveBeenCalled();
});

it("should handle case where user is on the wrong network", async () => {
mockUseDeployedContractInfo.mockReturnValue({
data: {
address: "0x123",
abi: [{ name: "testFunction" }],
},
});
const mockSendTransaction = { sendAsync: vi.fn() };
mochUseSendTransaction.mockReturnValue(mockSendTransaction);
mockUseTransactor.mockReturnValue(vi.fn());
mockUseTargetNetwork.mockReturnValue({
targetNetwork: { id: 2 }, // Different network ID
});

const { result } = renderHook(() =>
useScaffoldWriteContract({
contractName,
functionName,
args,
}),
);

await act(async () => {
await result.current.sendAsync();
});

expect(mockSendTransaction.sendAsync).not.toHaveBeenCalled();
});

it("should send transaction when contract is deployed and user is on correct network", async () => {
mockUseDeployedContractInfo.mockReturnValue({
data: {
address: "0x123",
abi: [{ name: "testFunction" }],
},
});
const mockSendTransaction = { sendAsync: vi.fn() };
mochUseSendTransaction.mockReturnValue(mockSendTransaction);
mockUseTransactor.mockReturnValue(vi.fn((fn) => fn()));
mockUseTargetNetwork.mockReturnValue({
targetNetwork: { id: 1 },
});

const { result } = renderHook(() =>
useScaffoldWriteContract({
contractName,
functionName,
args,
}),
);

await act(async () => {
await result.current.sendAsync();
});

expect(mockSendTransaction.sendAsync).toHaveBeenCalledWith([
{
contractAddress: "0x123",
entrypoint: functionName,
calldata: expect.any(Array),
},
]);
});

it("should call useDeployedContractInfo with the correct contract name", () => {
renderHook(() =>
useScaffoldWriteContract({
contractName,
functionName,
args,
}),
);

expect(useDeployedContractInfo).toHaveBeenCalledWith(contractName);
});
});

0 comments on commit 94327c7

Please sign in to comment.