@naculus/connect-appkit-react 0.1.9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +144 -0
- package/dist/client.d.ts +144 -0
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2270 -0
- package/dist/index.d.ts +2270 -0
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +30 -12
- package/api-extractor.json +0 -21
- package/src/chain-abstraction/index.ts +0 -8
- package/src/chain-abstraction/useCompareCosts.ts +0 -137
- package/src/chain-abstraction/useExecuteRoute.ts +0 -129
- package/src/chain-abstraction/useRouteQuote.ts +0 -168
- package/src/client.test.ts +0 -242
- package/src/client.ts +0 -265
- package/src/hooks/useAccount.test.ts +0 -67
- package/src/hooks/useAccount.ts +0 -37
- package/src/hooks/useBalance.test.ts +0 -459
- package/src/hooks/useBalance.ts +0 -170
- package/src/hooks/useChain.test.ts +0 -160
- package/src/hooks/useChain.ts +0 -53
- package/src/hooks/useConnect.test.ts +0 -112
- package/src/hooks/useConnect.ts +0 -29
- package/src/hooks/useDisconnect.test.ts +0 -75
- package/src/hooks/useDisconnect.ts +0 -32
- package/src/hooks/useERC20Allowance.ts +0 -93
- package/src/hooks/useERC20Approve.ts +0 -220
- package/src/hooks/useERC20Transfer.ts +0 -134
- package/src/hooks/useERC20TransferSimulation.ts +0 -147
- package/src/hooks/useEmbeddedWallet.test.ts +0 -266
- package/src/hooks/useEmbeddedWallet.ts +0 -181
- package/src/hooks/useLastTx.test.ts +0 -117
- package/src/hooks/useLastTx.ts +0 -73
- package/src/hooks/useLookupAddress.ts +0 -131
- package/src/hooks/useNotification.ts +0 -308
- package/src/hooks/useResolveName.ts +0 -128
- package/src/hooks/useSIWxLogin.test.ts +0 -307
- package/src/hooks/useSIWxLogin.ts +0 -163
- package/src/hooks/useSIWxSession.test.ts +0 -481
- package/src/hooks/useSIWxSession.ts +0 -290
- package/src/hooks/useSendCalls.ts +0 -103
- package/src/hooks/useSendTransaction.test.ts +0 -175
- package/src/hooks/useSendTransaction.ts +0 -80
- package/src/hooks/useSendUserOperation.ts +0 -313
- package/src/hooks/useSession.ts +0 -96
- package/src/hooks/useSessionKeys.ts +0 -356
- package/src/hooks/useSignInWithEthereum.test.ts +0 -224
- package/src/hooks/useSignInWithEthereum.ts +0 -46
- package/src/hooks/useSignInWithX.test.ts +0 -210
- package/src/hooks/useSignInWithX.ts +0 -141
- package/src/hooks/useSignMessage.test.ts +0 -151
- package/src/hooks/useSignMessage.ts +0 -65
- package/src/hooks/useSimulateTransfer.ts +0 -165
- package/src/hooks/useSiwxAuthSession.test.ts +0 -456
- package/src/hooks/useSiwxAuthSession.ts +0 -163
- package/src/hooks/useSmartAccount.ts +0 -194
- package/src/hooks/useSwitchChain.ts +0 -68
- package/src/hooks/useTokenBalance.test.ts +0 -337
- package/src/hooks/useTokenBalance.ts +0 -210
- package/src/hooks/useTransactionSimulation.ts +0 -401
- package/src/hooks/useTxHistory.test.ts +0 -108
- package/src/hooks/useTxHistory.ts +0 -83
- package/src/hooks/useTxMonitor.test.ts +0 -127
- package/src/hooks/useTxMonitor.ts +0 -178
- package/src/hooks/useUserOpStatus.ts +0 -245
- package/src/hooks/useValidateDestination.test.ts +0 -96
- package/src/hooks/useValidateDestination.ts +0 -72
- package/src/hooks/useViemClient.test.ts +0 -155
- package/src/hooks/useViemClient.ts +0 -65
- package/src/hooks/useWallet.test.ts +0 -133
- package/src/hooks/useWallet.ts +0 -39
- package/src/hooks/useWeb3ErrorHandler.ts +0 -102
- package/src/index.ts +0 -186
- package/src/provider/Web3ConnectProvider.test.tsx +0 -178
- package/src/provider/Web3ConnectProvider.tsx +0 -530
- package/src/token-list/TokenSelector.tsx +0 -351
- package/src/token-list/defaults.ts +0 -39
- package/src/token-list/index.ts +0 -14
- package/src/token-list/useTokenList.ts +0 -119
- package/src/token-list/useTokenSearch.ts +0 -99
- package/src/types/index.ts +0 -99
- package/src/utils/chains.ts +0 -115
- package/src/utils/errorMessages.ts +0 -142
- package/src/utils/i18n.ts +0 -90
- package/src/wc-generated/components.ts +0 -377
- package/test/setup.ts +0 -17
- package/test/test-utils.tsx +0 -78
- package/tsup.config.ts +0 -18
|
@@ -1,481 +0,0 @@
|
|
|
1
|
-
/// <reference types="vitest" />
|
|
2
|
-
/// @vitest-environment jsdom
|
|
3
|
-
|
|
4
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
5
|
-
import { renderHook, act, waitFor } from "@testing-library/react";
|
|
6
|
-
|
|
7
|
-
// ── localStorage polyfill for Node 26 ────────────────────────────
|
|
8
|
-
|
|
9
|
-
if (typeof globalThis.localStorage === 'undefined') {
|
|
10
|
-
const store: Record<string, string> = {};
|
|
11
|
-
const lsMock = {
|
|
12
|
-
getItem: (key: string) => store[key] ?? null,
|
|
13
|
-
setItem: (key: string, value: string) => { store[key] = value; },
|
|
14
|
-
removeItem: (key: string) => { delete store[key]; },
|
|
15
|
-
clear: () => { Object.keys(store).forEach(k => delete store[k]); },
|
|
16
|
-
get length() { return Object.keys(store).length; },
|
|
17
|
-
key: (index: number) => Object.keys(store)[index] ?? null,
|
|
18
|
-
};
|
|
19
|
-
Object.defineProperty(globalThis, 'localStorage', {
|
|
20
|
-
value: new Proxy(lsMock, {
|
|
21
|
-
ownKeys: () => Object.keys(store),
|
|
22
|
-
getOwnPropertyDescriptor: () => ({ configurable: true, enumerable: true }),
|
|
23
|
-
}),
|
|
24
|
-
writable: true, configurable: true,
|
|
25
|
-
});
|
|
26
|
-
if (typeof window !== 'undefined') {
|
|
27
|
-
Object.defineProperty(window, 'localStorage', {
|
|
28
|
-
value: new Proxy(lsMock, {
|
|
29
|
-
ownKeys: () => Object.keys(store),
|
|
30
|
-
getOwnPropertyDescriptor: () => ({ configurable: true, enumerable: true }),
|
|
31
|
-
}),
|
|
32
|
-
writable: true, configurable: true,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ── Mocks ────────────────────────────────────────────────────────
|
|
38
|
-
|
|
39
|
-
// Mock @naculus/connect-core to avoid @noble/hashes issues
|
|
40
|
-
vi.mock("@naculus/connect-core", () => ({
|
|
41
|
-
WalletError: class WalletError extends Error {
|
|
42
|
-
code: string;
|
|
43
|
-
constructor(code: string, message: string) {
|
|
44
|
-
super(message);
|
|
45
|
-
this.name = "WalletError";
|
|
46
|
-
this.code = code;
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
|
|
50
|
-
LocalStorageAdapter: vi.fn().mockImplementation(() => ({
|
|
51
|
-
get: vi.fn(),
|
|
52
|
-
set: vi.fn(),
|
|
53
|
-
remove: vi.fn(),
|
|
54
|
-
clear: vi.fn(),
|
|
55
|
-
isAvailable: vi.fn(() => true),
|
|
56
|
-
})),
|
|
57
|
-
}));
|
|
58
|
-
|
|
59
|
-
// Mock @naculus/siwx to avoid transitive dependency chain issues
|
|
60
|
-
vi.mock("@naculus/siwx", () => {
|
|
61
|
-
const mockCreateSiwxMessage = vi.fn((params) => {
|
|
62
|
-
const lines = [
|
|
63
|
-
`${params.domain} wants you to sign in with your ${params.blockchain ?? "blockchain"} account:`,
|
|
64
|
-
params.address,
|
|
65
|
-
...(params.statement ? ["", params.statement] : []),
|
|
66
|
-
"",
|
|
67
|
-
`URI: ${params.uri}`,
|
|
68
|
-
`Version: ${params.version ?? 1}`,
|
|
69
|
-
`Chain ID: ${params.chainId}`,
|
|
70
|
-
`Nonce: ${params.nonce}`,
|
|
71
|
-
`Issued At: ${params.issuedAt}`,
|
|
72
|
-
];
|
|
73
|
-
return lines.join("\n");
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const mockCheckSessionExpired = vi.fn((session: any) => {
|
|
77
|
-
if (!session) return true;
|
|
78
|
-
if (!session.expiresAt) return false;
|
|
79
|
-
return new Date(session.expiresAt).getTime() <= Date.now();
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
function makeLocalStorageStorage(key: string) {
|
|
83
|
-
return {
|
|
84
|
-
async get() {
|
|
85
|
-
const raw = localStorage.getItem(key);
|
|
86
|
-
if (!raw) return null;
|
|
87
|
-
try {
|
|
88
|
-
const session = JSON.parse(raw);
|
|
89
|
-
if (session.expiresAt && new Date(session.expiresAt).getTime() <= Date.now()) {
|
|
90
|
-
localStorage.removeItem(key);
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
return session;
|
|
94
|
-
} catch {
|
|
95
|
-
localStorage.removeItem(key);
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
async set(session: any) {
|
|
100
|
-
localStorage.setItem(key, JSON.stringify(session));
|
|
101
|
-
},
|
|
102
|
-
async remove() {
|
|
103
|
-
localStorage.removeItem(key);
|
|
104
|
-
},
|
|
105
|
-
async has() {
|
|
106
|
-
return localStorage.getItem(key) !== null;
|
|
107
|
-
},
|
|
108
|
-
async clear() {
|
|
109
|
-
localStorage.removeItem(key);
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
createSiwxMessage: mockCreateSiwxMessage,
|
|
116
|
-
generateNonce: vi.fn(() => "mockNonce123"),
|
|
117
|
-
nowISO: vi.fn(() => new Date().toISOString()),
|
|
118
|
-
getBlockchainName: vi.fn((chainId) => {
|
|
119
|
-
if (chainId.startsWith("eip155:")) return "Ethereum";
|
|
120
|
-
if (chainId.startsWith("solana:")) return "Solana";
|
|
121
|
-
if (chainId.startsWith("xrpl:")) return "XRP Ledger";
|
|
122
|
-
return "blockchain";
|
|
123
|
-
}),
|
|
124
|
-
checkSessionExpired: mockCheckSessionExpired,
|
|
125
|
-
createLocalStorageSiwxSessionStorage: vi.fn((key) => makeLocalStorageStorage(key)),
|
|
126
|
-
createMemorySiwxSessionStorage: vi.fn(() => {
|
|
127
|
-
const store = new Map<string, string>();
|
|
128
|
-
return {
|
|
129
|
-
async get() { return null; },
|
|
130
|
-
async set(session: any) {},
|
|
131
|
-
async remove() {},
|
|
132
|
-
async has() { return false; },
|
|
133
|
-
async clear() {},
|
|
134
|
-
};
|
|
135
|
-
}),
|
|
136
|
-
SiwxSessionManager: vi.fn(),
|
|
137
|
-
DEFAULT_SESSION_EXPIRY_SECONDS: 86_400,
|
|
138
|
-
DEFAULT_SESSION_STORAGE_KEY: "naculus_siwx_session",
|
|
139
|
-
};
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
const mockUseWeb3 = vi.fn();
|
|
143
|
-
vi.mock("../provider/Web3ConnectProvider", () => ({
|
|
144
|
-
useWeb3: () => mockUseWeb3(),
|
|
145
|
-
Web3ConnectProvider: ({ children }: { children: React.ReactNode }) => children,
|
|
146
|
-
}));
|
|
147
|
-
|
|
148
|
-
const mockSignMessage = vi.fn();
|
|
149
|
-
const mockGetClient = vi.fn();
|
|
150
|
-
vi.mock("../client", () => ({
|
|
151
|
-
getClient: () => mockGetClient(),
|
|
152
|
-
}));
|
|
153
|
-
|
|
154
|
-
import { useSIWxSession } from "./useSIWxSession";
|
|
155
|
-
|
|
156
|
-
// ── Test Fixtures ────────────────────────────────────────────────
|
|
157
|
-
|
|
158
|
-
function createSiwxSession(overrides: Record<string, unknown> = {}) {
|
|
159
|
-
const expiresAt = new Date(Date.now() + 3600_000).toISOString(); // 1h from now
|
|
160
|
-
const messageOverrides = (overrides.message as Record<string, unknown> | undefined) ?? {};
|
|
161
|
-
return {
|
|
162
|
-
id: "siwx_test_abc",
|
|
163
|
-
chainId: "eip155:1",
|
|
164
|
-
address: "eip155:1:0x1234567890123456789012345678901234567890",
|
|
165
|
-
domain: "localhost",
|
|
166
|
-
message: {
|
|
167
|
-
raw: "localhost wants you to sign in with your Ethereum account:...",
|
|
168
|
-
domain: "localhost",
|
|
169
|
-
address: "eip155:1:0x1234567890123456789012345678901234567890",
|
|
170
|
-
statement: "Sign in to test",
|
|
171
|
-
uri: "http://localhost",
|
|
172
|
-
version: 1,
|
|
173
|
-
chainId: "eip155:1",
|
|
174
|
-
nonce: "abc123xyz",
|
|
175
|
-
issuedAt: new Date().toISOString(),
|
|
176
|
-
expirationTime: expiresAt,
|
|
177
|
-
notBefore: null,
|
|
178
|
-
resources: [],
|
|
179
|
-
requestId: null,
|
|
180
|
-
blockchain: "Ethereum",
|
|
181
|
-
...messageOverrides,
|
|
182
|
-
},
|
|
183
|
-
signature: "0xdeadbeef",
|
|
184
|
-
issuedAt: new Date().toISOString(),
|
|
185
|
-
expiresAt,
|
|
186
|
-
refreshedAt: null,
|
|
187
|
-
...overrides,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// ── Storage Helpers ──────────────────────────────────────────────
|
|
192
|
-
|
|
193
|
-
function setLocalStorage(key: string, value: unknown) {
|
|
194
|
-
localStorage.setItem(key, JSON.stringify(value));
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function getLocalStorage(key: string) {
|
|
198
|
-
const v = localStorage.getItem(key);
|
|
199
|
-
return v ? JSON.parse(v) : null;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function clearLocalStorage() {
|
|
203
|
-
const keys = Object.keys(localStorage);
|
|
204
|
-
keys.forEach((k) => localStorage.removeItem(k));
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// ── Tests ───────────────────────────────────────────────────────
|
|
208
|
-
|
|
209
|
-
describe("useSIWxSession", () => {
|
|
210
|
-
beforeEach(() => {
|
|
211
|
-
vi.clearAllMocks();
|
|
212
|
-
clearLocalStorage();
|
|
213
|
-
|
|
214
|
-
mockSignMessage.mockResolvedValue("0xmock_sig");
|
|
215
|
-
mockUseWeb3.mockReturnValue({
|
|
216
|
-
session: {
|
|
217
|
-
topic: "test-topic",
|
|
218
|
-
namespaces: {
|
|
219
|
-
eip155: {
|
|
220
|
-
chains: ["eip155:1"],
|
|
221
|
-
accounts: ["eip155:1:0x1234567890123456789012345678901234567890"],
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
},
|
|
225
|
-
chainId: "eip155:1",
|
|
226
|
-
});
|
|
227
|
-
mockGetClient.mockReturnValue({ signMessage: mockSignMessage });
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
afterEach(() => {
|
|
231
|
-
clearLocalStorage();
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// ── Initial State ──────────────────────────────────────────────
|
|
235
|
-
|
|
236
|
-
it("should have initial unauthenticated state", () => {
|
|
237
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
238
|
-
|
|
239
|
-
expect(result.current.isAuthenticated).toBe(false);
|
|
240
|
-
expect(result.current.session).toBeNull();
|
|
241
|
-
expect(result.current.isSigningIn).toBe(false);
|
|
242
|
-
expect(result.current.error).toBeNull();
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
it("should be restoring when autoRestore is true", () => {
|
|
246
|
-
const { result } = renderHook(() => useSIWxSession());
|
|
247
|
-
|
|
248
|
-
expect(result.current.isRestoring).toBe(true);
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
it("should finish restoring when no saved auth exists", async () => {
|
|
252
|
-
const { result } = renderHook(() => useSIWxSession());
|
|
253
|
-
|
|
254
|
-
await waitFor(() => {
|
|
255
|
-
expect(result.current.isRestoring).toBe(false);
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
expect(result.current.isAuthenticated).toBe(false);
|
|
259
|
-
expect(result.current.session).toBeNull();
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
// ── Persisted Session Restore ──────────────────────────────────
|
|
263
|
-
|
|
264
|
-
it("should restore a valid persisted session", async () => {
|
|
265
|
-
const session = createSiwxSession();
|
|
266
|
-
setLocalStorage("naculus_siwx_session", session);
|
|
267
|
-
|
|
268
|
-
const { result } = renderHook(() => useSIWxSession());
|
|
269
|
-
|
|
270
|
-
await waitFor(() => {
|
|
271
|
-
expect(result.current.isRestoring).toBe(false);
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
expect(result.current.isAuthenticated).toBe(true);
|
|
275
|
-
expect(result.current.session).not.toBeNull();
|
|
276
|
-
expect(result.current.session!.signature).toBe("0xdeadbeef");
|
|
277
|
-
expect(result.current.error).toBeNull();
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it("should not restore when autoRestore is false", async () => {
|
|
281
|
-
setLocalStorage("naculus_siwx_session", createSiwxSession());
|
|
282
|
-
|
|
283
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
284
|
-
|
|
285
|
-
await waitFor(() => {
|
|
286
|
-
expect(result.current.isRestoring).toBe(false);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
expect(result.current.isAuthenticated).toBe(false);
|
|
290
|
-
expect(result.current.session).toBeNull();
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
it("should discard expired persisted session", async () => {
|
|
294
|
-
const expired = createSiwxSession({
|
|
295
|
-
message: {
|
|
296
|
-
expirationTime: new Date(Date.now() - 10_000).toISOString(),
|
|
297
|
-
},
|
|
298
|
-
expiresAt: new Date(Date.now() - 10_000).toISOString(),
|
|
299
|
-
});
|
|
300
|
-
setLocalStorage("naculus_siwx_session", expired);
|
|
301
|
-
|
|
302
|
-
const { result } = renderHook(() => useSIWxSession());
|
|
303
|
-
|
|
304
|
-
await waitFor(() => {
|
|
305
|
-
expect(result.current.isRestoring).toBe(false);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
expect(result.current.isAuthenticated).toBe(false);
|
|
309
|
-
expect(result.current.session).toBeNull();
|
|
310
|
-
|
|
311
|
-
// Should be cleaned from storage
|
|
312
|
-
expect(getLocalStorage("naculus_siwx_session")).toBeNull();
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
// ── Sign In ────────────────────────────────────────────────────
|
|
316
|
-
|
|
317
|
-
it("should sign in and persist session", async () => {
|
|
318
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
319
|
-
|
|
320
|
-
let session: Awaited<ReturnType<typeof result.current.signIn>> | undefined;
|
|
321
|
-
|
|
322
|
-
await act(async () => {
|
|
323
|
-
session = await result.current.signIn({ statement: "Test sign-in" });
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
expect(session).toBeDefined();
|
|
327
|
-
expect(session!.id).toMatch(/^siwx_/);
|
|
328
|
-
expect(session!.chainId).toBe("eip155:1");
|
|
329
|
-
expect(session!.signature).toBe("0xmock_sig");
|
|
330
|
-
expect(result.current.isAuthenticated).toBe(true);
|
|
331
|
-
|
|
332
|
-
// Verify persistence
|
|
333
|
-
const stored = getLocalStorage("naculus_siwx_session");
|
|
334
|
-
expect(stored).not.toBeNull();
|
|
335
|
-
expect(stored.id).toBe(session!.id);
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it("should handle sign-in failure", async () => {
|
|
339
|
-
mockSignMessage.mockRejectedValue(new Error("User rejected"));
|
|
340
|
-
|
|
341
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
342
|
-
|
|
343
|
-
await act(async () => {
|
|
344
|
-
try {
|
|
345
|
-
await result.current.signIn();
|
|
346
|
-
} catch {
|
|
347
|
-
// Expected
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
expect(result.current.isAuthenticated).toBe(false);
|
|
352
|
-
expect(result.current.error).not.toBeNull();
|
|
353
|
-
expect(result.current.error!.message).toBe("User rejected");
|
|
354
|
-
|
|
355
|
-
// Should NOT persist anything
|
|
356
|
-
expect(getLocalStorage("naculus_siwx_session")).toBeNull();
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
// ── Sign Out ───────────────────────────────────────────────────
|
|
360
|
-
|
|
361
|
-
it("should clear session on sign-out", async () => {
|
|
362
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
363
|
-
|
|
364
|
-
await act(async () => {
|
|
365
|
-
await result.current.signIn();
|
|
366
|
-
});
|
|
367
|
-
expect(result.current.isAuthenticated).toBe(true);
|
|
368
|
-
|
|
369
|
-
await act(async () => {
|
|
370
|
-
await result.current.signOut();
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
expect(result.current.isAuthenticated).toBe(false);
|
|
374
|
-
expect(result.current.session).toBeNull();
|
|
375
|
-
expect(getLocalStorage("naculus_siwx_session")).toBeNull();
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
// ── Refresh ────────────────────────────────────────────────────
|
|
379
|
-
|
|
380
|
-
it("should refresh an active session", async () => {
|
|
381
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
382
|
-
|
|
383
|
-
await act(async () => {
|
|
384
|
-
await result.current.signIn({ statement: "Initial" });
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
const originalSession = result.current.session!;
|
|
388
|
-
const originalId = originalSession.id;
|
|
389
|
-
|
|
390
|
-
await act(async () => {
|
|
391
|
-
const refreshed = await result.current.refresh();
|
|
392
|
-
expect(refreshed.id).toBe(originalId);
|
|
393
|
-
expect(refreshed.refreshedAt).not.toBeNull();
|
|
394
|
-
expect(refreshed.signature).toBe("0xmock_sig");
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
expect(result.current.isAuthenticated).toBe(true);
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
it("should throw on refresh when no session exists", async () => {
|
|
401
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
402
|
-
|
|
403
|
-
await expect(result.current.refresh()).rejects.toThrow("No active session to refresh");
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
// ── Expiry / Time ──────────────────────────────────────────────
|
|
407
|
-
|
|
408
|
-
it("should report isExpired correctly", async () => {
|
|
409
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
410
|
-
|
|
411
|
-
// No session → expired
|
|
412
|
-
expect(result.current.isExpired).toBe(true);
|
|
413
|
-
|
|
414
|
-
await act(async () => {
|
|
415
|
-
await result.current.signIn();
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
// Active session → not expired
|
|
419
|
-
expect(result.current.isExpired).toBe(false);
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
it("should report timeUntilExpiry correctly", async () => {
|
|
423
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
424
|
-
|
|
425
|
-
// No session → null
|
|
426
|
-
expect(result.current.timeUntilExpiry).toBeNull();
|
|
427
|
-
|
|
428
|
-
await act(async () => {
|
|
429
|
-
await result.current.signIn();
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
// Active session → positive number
|
|
433
|
-
expect(result.current.timeUntilExpiry! > 0).toBe(true);
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
// ── Error Handling ─────────────────────────────────────────────
|
|
437
|
-
|
|
438
|
-
it("should clear error via clearError", async () => {
|
|
439
|
-
mockSignMessage.mockRejectedValue(new Error("Temporary error"));
|
|
440
|
-
|
|
441
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
442
|
-
|
|
443
|
-
await act(async () => {
|
|
444
|
-
try {
|
|
445
|
-
await result.current.signIn();
|
|
446
|
-
} catch {
|
|
447
|
-
// Expected
|
|
448
|
-
}
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
expect(result.current.error).not.toBeNull();
|
|
452
|
-
|
|
453
|
-
act(() => {
|
|
454
|
-
result.current.clearError();
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
expect(result.current.error).toBeNull();
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
// ── Sign-In After Sign-Out ─────────────────────────────────────
|
|
461
|
-
|
|
462
|
-
it("should allow sign-in after sign-out", async () => {
|
|
463
|
-
const { result } = renderHook(() => useSIWxSession({ autoRestore: false }));
|
|
464
|
-
|
|
465
|
-
await act(async () => {
|
|
466
|
-
await result.current.signIn({ statement: "First" });
|
|
467
|
-
});
|
|
468
|
-
expect(result.current.isAuthenticated).toBe(true);
|
|
469
|
-
|
|
470
|
-
await act(async () => {
|
|
471
|
-
await result.current.signOut();
|
|
472
|
-
});
|
|
473
|
-
expect(result.current.isAuthenticated).toBe(false);
|
|
474
|
-
|
|
475
|
-
await act(async () => {
|
|
476
|
-
await result.current.signIn({ statement: "Second" });
|
|
477
|
-
});
|
|
478
|
-
expect(result.current.isAuthenticated).toBe(true);
|
|
479
|
-
expect(result.current.session!.message.statement).toBe("Second");
|
|
480
|
-
});
|
|
481
|
-
});
|