@gemini-wallet/core
Version:
Core SDK for Gemini Wallet integration with popup communication
162 lines (134 loc) • 5.39 kB
text/typescript
import { describe, expect, test, mock } from "bun:test";
import { GeminiWalletProvider } from "./provider";
import { GeminiStorage } from "@/storage";
import type { GeminiProviderConfig } from "@/types";
describe("GeminiProviderConfig", () => {
const createMockConfig = (overrides: Partial<GeminiProviderConfig> = {}): GeminiProviderConfig => ({
appMetadata: {
name: "Test App",
description: "Test Description",
url: "https://test.com",
icons: []
},
chain: { id: 1 },
storage: new GeminiStorage(),
...overrides
});
test("should preserve user's onDisconnectCallback and call provider cleanup", async () => {
const userDisconnectCallback = mock();
let providerDisconnectCalled = false;
const provider = new GeminiWalletProvider(createMockConfig({
onDisconnectCallback: userDisconnectCallback
}));
// Mock the provider disconnect to track if it's called
const originalDisconnect = provider.disconnect;
provider.disconnect = async () => {
providerDisconnectCalled = true;
return originalDisconnect.call(provider);
};
// Simulate disconnect through the wallet's callback mechanism
// @ts-ignore - accessing private property for testing
if (provider.wallet?.communicator) {
// @ts-ignore - accessing private property for testing
provider.wallet.communicator.onDisconnectCallback?.();
}
expect(userDisconnectCallback).toHaveBeenCalledTimes(1);
expect(providerDisconnectCalled).toBe(true);
});
test("should handle missing user onDisconnectCallback gracefully", async () => {
let providerDisconnectCalled = false;
const provider = new GeminiWalletProvider(createMockConfig({
// No onDisconnectCallback provided
}));
// Mock the provider disconnect to track if it's called
const originalDisconnect = provider.disconnect;
provider.disconnect = async () => {
providerDisconnectCalled = true;
return originalDisconnect.call(provider);
};
// Simulate disconnect through the wallet's callback mechanism
// @ts-ignore - accessing private property for testing
if (provider.wallet?.communicator) {
// @ts-ignore - accessing private property for testing
provider.wallet.communicator.onDisconnectCallback?.();
}
expect(providerDisconnectCalled).toBe(true);
});
test("should store complete config internally", () => {
const config = createMockConfig({
appMetadata: {
name: "Custom App",
description: "Custom Description",
url: "https://custom.com",
icons: ["icon1.png", "icon2.png"]
},
chain: {
id: 42161,
rpcUrl: "https://custom-rpc.example.com"
}
});
const provider = new GeminiWalletProvider(config);
expect(provider).toBeDefined();
// @ts-ignore - accessing private property for testing
expect(provider.config).toEqual(config);
});
test("should pass config correctly to wallet constructor", () => {
const customStorage = new GeminiStorage();
const config = createMockConfig({
chain: {
id: 137, // Polygon
rpcUrl: "https://polygon-rpc.example.com"
},
storage: customStorage
});
const provider = new GeminiWalletProvider(config);
expect(provider).toBeDefined();
// @ts-ignore - accessing private property for testing
expect(provider.wallet?.storage).toBe(customStorage);
});
test("should handle wallet recreation with preserved user callback", async () => {
const userDisconnectCallback = mock();
let providerDisconnectCallCount = 0;
const provider = new GeminiWalletProvider(createMockConfig({
onDisconnectCallback: userDisconnectCallback
}));
// Mock the provider disconnect to count calls
const originalDisconnect = provider.disconnect;
provider.disconnect = async () => {
providerDisconnectCallCount++;
return originalDisconnect.call(provider);
};
// Set wallet to undefined to trigger recreation
// @ts-ignore - accessing private property for testing
provider.wallet = undefined;
// Simulate eth_requestAccounts which recreates wallet
try {
await provider.request({ method: "eth_requestAccounts" });
} catch (error) {
// Expected to fail in test environment, but wallet should be recreated
}
// Verify wallet was recreated
// @ts-ignore - accessing private property for testing
expect(provider.wallet).toBeDefined();
// Test that the recreated wallet still has the user callback
// @ts-ignore - accessing private property for testing
if (provider.wallet?.communicator) {
// @ts-ignore - accessing private property for testing
provider.wallet.communicator.onDisconnectCallback?.();
}
expect(userDisconnectCallback).toHaveBeenCalled();
expect(providerDisconnectCallCount).toBeGreaterThan(0);
});
test("should support custom chain configuration", () => {
const customChain = {
id: 8453, // Base
rpcUrl: "https://base-mainnet.example.com"
};
const provider = new GeminiWalletProvider(createMockConfig({
chain: customChain
}));
expect(provider).toBeDefined();
// @ts-ignore - accessing private property for testing
expect(provider.config.chain).toEqual(customChain);
});
});