Skip to content

Commit 77c8d0e

Browse files
test: Add wallet connection hook tests (#5689)
1 parent 29d32b8 commit 77c8d0e

File tree

4 files changed

+231
-4
lines changed

4 files changed

+231
-4
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { renderHook } from "@testing-library/react";
2+
import type { ReactNode } from "react";
3+
import { describe, expect, it } from "vitest";
4+
import { MockStorage } from "../../../../../test/src/mocks/storage.js";
5+
import { TEST_CLIENT } from "../../../../../test/src/test-clients.js";
6+
import { TEST_ACCOUNT_A } from "../../../../../test/src/test-wallets.js";
7+
import { createWalletAdapter } from "../../../../adapters/wallet-adapter.js";
8+
import { ethereum } from "../../../../chains/chain-definitions/ethereum.js";
9+
import { createConnectionManager } from "../../../../wallets/manager/index.js";
10+
import { ConnectionManagerCtx } from "../../providers/connection-manager.js";
11+
import { useAddConnectedWallet } from "./useAddConnectedWallet.js";
12+
13+
describe("useAddConnectedWallet", () => {
14+
// Mock the connection manager
15+
const mockStorage = new MockStorage();
16+
const manager = createConnectionManager(mockStorage);
17+
18+
// Create a wrapper component with the mocked context
19+
const wrapper = ({ children }: { children: ReactNode }) => {
20+
return (
21+
<ConnectionManagerCtx.Provider value={manager}>
22+
{children}
23+
</ConnectionManagerCtx.Provider>
24+
);
25+
};
26+
27+
const wallet = createWalletAdapter({
28+
adaptedAccount: TEST_ACCOUNT_A,
29+
client: TEST_CLIENT,
30+
chain: ethereum,
31+
onDisconnect: () => {},
32+
switchChain: () => {},
33+
});
34+
35+
it("should add a wallet to the connection manager", async () => {
36+
// Render the hook
37+
const { result } = renderHook(() => useAddConnectedWallet(), { wrapper });
38+
result.current(wallet);
39+
40+
expect(manager.connectedWallets.getValue()).toHaveLength(1);
41+
expect(manager.connectedWallets.getValue()[0]).toEqual(wallet);
42+
// add connected wallet should not set the active wallet
43+
expect(manager.activeWalletStore.getValue()).toBeUndefined();
44+
});
45+
46+
it("should throw an error when used outside of ThirdwebProvider", () => {
47+
// Render the hook without a provider
48+
expect(() => {
49+
renderHook(() => useAddConnectedWallet());
50+
}).toThrow("useAddConnectedWallet must be used within <ThirdwebProvider>");
51+
});
52+
});
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { renderHook } from "@testing-library/react";
2+
import type { ReactNode } from "react";
3+
import { beforeEach, describe, expect, it } from "vitest";
4+
import { MockStorage } from "../../../../../test/src/mocks/storage.js";
5+
import { TEST_CLIENT } from "../../../../../test/src/test-clients.js";
6+
import { TEST_ACCOUNT_A } from "../../../../../test/src/test-wallets.js";
7+
import { createWalletAdapter } from "../../../../adapters/wallet-adapter.js";
8+
import { ethereum } from "../../../../chains/chain-definitions/ethereum.js";
9+
import {
10+
type ConnectionManager,
11+
createConnectionManager,
12+
} from "../../../../wallets/manager/index.js";
13+
import { ConnectionManagerCtx } from "../../providers/connection-manager.js";
14+
import { useActiveWalletConnectionStatus } from "./useActiveWalletConnectionStatus.js";
15+
import { useConnect } from "./useConnect.js";
16+
17+
describe("useAddConnectedWallet", () => {
18+
// Mock the connection manager
19+
const mockStorage = new MockStorage();
20+
let manager: ConnectionManager;
21+
22+
// Create a wrapper component with the mocked context
23+
const wrapper = ({ children }: { children: ReactNode }) => {
24+
return (
25+
<ConnectionManagerCtx.Provider value={manager}>
26+
{children}
27+
</ConnectionManagerCtx.Provider>
28+
);
29+
};
30+
31+
const wallet = createWalletAdapter({
32+
adaptedAccount: TEST_ACCOUNT_A,
33+
client: TEST_CLIENT,
34+
chain: ethereum,
35+
onDisconnect: () => {},
36+
switchChain: () => {},
37+
});
38+
39+
beforeEach(() => {
40+
manager = createConnectionManager(mockStorage);
41+
});
42+
43+
it("should connect a wallet to the connection manager", async () => {
44+
const { result: statusResult } = renderHook(
45+
() => useActiveWalletConnectionStatus(),
46+
{
47+
wrapper,
48+
},
49+
);
50+
const { result } = renderHook(() => useConnect(), { wrapper });
51+
expect(statusResult.current).toEqual("disconnected");
52+
await result.current.connect(async () => wallet);
53+
expect(statusResult.current).toEqual("connected");
54+
55+
// should add to connected wallets
56+
expect(manager.connectedWallets.getValue()).toHaveLength(1);
57+
expect(manager.connectedWallets.getValue()[0]).toEqual(wallet);
58+
// should set the active wallet
59+
expect(manager.activeWalletStore.getValue()).toEqual(wallet);
60+
});
61+
62+
it("should handle a function that returns a wallet", async () => {
63+
const { result: statusResult } = renderHook(
64+
() => useActiveWalletConnectionStatus(),
65+
{
66+
wrapper,
67+
},
68+
);
69+
const { result } = renderHook(() => useConnect(), { wrapper });
70+
expect(statusResult.current).toEqual("disconnected");
71+
await result.current.connect(async () => wallet);
72+
expect(statusResult.current).toEqual("connected");
73+
74+
// should add to connected wallets
75+
expect(manager.connectedWallets.getValue()).toHaveLength(1);
76+
expect(manager.connectedWallets.getValue()[0]).toEqual(wallet);
77+
// should set the active wallet
78+
expect(manager.activeWalletStore.getValue()).toEqual(wallet);
79+
});
80+
81+
it("should handle an error when connecting a wallet", async () => {
82+
const { result: statusResult } = renderHook(
83+
() => useActiveWalletConnectionStatus(),
84+
{
85+
wrapper,
86+
},
87+
);
88+
expect(statusResult.current).toEqual("disconnected");
89+
const { result } = renderHook(() => useConnect(), { wrapper });
90+
await result.current.connect(async () => {
91+
throw new Error("test");
92+
});
93+
94+
expect(statusResult.current).toEqual("disconnected");
95+
// should set the active wallet
96+
expect(manager.activeWalletStore.getValue()).toEqual(undefined);
97+
});
98+
99+
it("should throw an error when used outside of ThirdwebProvider", () => {
100+
// Render the hook without a provider
101+
expect(() => {
102+
renderHook(() => useConnect());
103+
}).toThrow("useConnect must be used within <ThirdwebProvider>");
104+
});
105+
});
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { renderHook } from "@testing-library/react";
2+
import type { ReactNode } from "react";
3+
import { describe, expect, it } from "vitest";
4+
import { MockStorage } from "../../../../../test/src/mocks/storage.js";
5+
import { TEST_CLIENT } from "../../../../../test/src/test-clients.js";
6+
import { TEST_ACCOUNT_A } from "../../../../../test/src/test-wallets.js";
7+
import { createWalletAdapter } from "../../../../adapters/wallet-adapter.js";
8+
import { ethereum } from "../../../../chains/chain-definitions/ethereum.js";
9+
import { createConnectionManager } from "../../../../wallets/manager/index.js";
10+
import { ConnectionManagerCtx } from "../../providers/connection-manager.js";
11+
import { useSetActiveWallet } from "./useSetActiveWallet.js";
12+
13+
describe("useAddConnectedWallet", () => {
14+
// Mock the connection manager
15+
const mockStorage = new MockStorage();
16+
const manager = createConnectionManager(mockStorage);
17+
18+
// Create a wrapper component with the mocked context
19+
const wrapper = ({ children }: { children: ReactNode }) => {
20+
return (
21+
<ConnectionManagerCtx.Provider value={manager}>
22+
{children}
23+
</ConnectionManagerCtx.Provider>
24+
);
25+
};
26+
27+
const wallet = createWalletAdapter({
28+
adaptedAccount: TEST_ACCOUNT_A,
29+
client: TEST_CLIENT,
30+
chain: ethereum,
31+
onDisconnect: () => {},
32+
switchChain: () => {},
33+
});
34+
35+
it("should add a wallet to the connection manager", async () => {
36+
// Render the hook
37+
const { result } = renderHook(() => useSetActiveWallet(), { wrapper });
38+
result.current(wallet);
39+
40+
// should add to connected wallets
41+
expect(manager.connectedWallets.getValue()).toHaveLength(1);
42+
expect(manager.connectedWallets.getValue()[0]).toEqual(wallet);
43+
// should set the active wallet
44+
expect(manager.activeWalletStore.getValue()).toEqual(wallet);
45+
});
46+
47+
it("should throw an error when used outside of ThirdwebProvider", () => {
48+
// Render the hook without a provider
49+
expect(() => {
50+
renderHook(() => useSetActiveWallet());
51+
}).toThrow("useSetActiveWallet must be used within <ThirdwebProvider>");
52+
});
53+
});

packages/thirdweb/test/src/mocks/storage.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import { http, HttpResponse } from "msw";
22
import { getThirdwebDomains } from "../../../src/utils/domains.js";
3+
import type { AsyncStorage } from "../../../src/utils/storage/AsyncStorage.js";
34

45
export const handlers = [
56
http.post(
67
`https://${getThirdwebDomains().storage}/ipfs/upload`,
78
async ({ request }) => {
89
console.log("MSW handler hit for IPFS upload");
910
const formData = await request.formData();
10-
const files = formData.getAll('file');
11+
const files = formData.getAll("file");
1112
const fileNames = files.map((file: any) => file.name);
12-
13+
1314
const mockIpfsHash = "QmTest1234567890TestHash";
14-
15+
1516
if (fileNames.length === 1 && fileNames[0] === "file.txt") {
1617
return HttpResponse.json({ IpfsHash: mockIpfsHash });
1718
} else {
@@ -20,7 +21,7 @@ export const handlers = [
2021
files: fileNames.reduce((acc, fileName) => {
2122
acc[fileName] = { cid: mockIpfsHash };
2223
return acc;
23-
}, {})
24+
}, {}),
2425
});
2526
}
2627
},
@@ -40,3 +41,19 @@ export const handlers = [
4041
});
4142
}),
4243
];
44+
45+
export class MockStorage implements AsyncStorage {
46+
private storage: Map<string, string> = new Map();
47+
48+
getItem(key: string): Promise<string | null> {
49+
return Promise.resolve(this.storage.get(key) ?? null);
50+
}
51+
setItem(key: string, value: string): Promise<void> {
52+
this.storage.set(key, value);
53+
return Promise.resolve();
54+
}
55+
removeItem(key: string): Promise<void> {
56+
this.storage.delete(key);
57+
return Promise.resolve();
58+
}
59+
}

0 commit comments

Comments
 (0)