-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: create test for useScaffoldWriteContract hook (#316)
- Loading branch information
Showing
2 changed files
with
389 additions
and
0 deletions.
There are no files selected for viewing
243 changes: 243 additions & 0 deletions
243
packages/nextjs/hooks/scaffold-stark/__tests__/useScaffoldMultiWriteContract.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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], | ||
}); | ||
}); | ||
}); |
146 changes: 146 additions & 0 deletions
146
packages/nextjs/hooks/scaffold-stark/__tests__/useScaffoldWriteContract.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}); | ||
}); |