Skip to content

Commit 9ed2034

Browse files
committed
test: add cloud restore hook tests
1 parent a7cc28c commit 9ed2034

1 file changed

Lines changed: 124 additions & 0 deletions

File tree

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { renderHook, waitFor } from "@testing-library/react-native"
2+
3+
import { useCloudRestore } from "@app/screens/spark-onboarding/restore/hooks/use-cloud-restore"
4+
5+
const mockStartSession = jest.fn()
6+
const mockDownload = jest.fn()
7+
const mockRestore = jest.fn()
8+
const mockRecordError = jest.fn()
9+
10+
jest.mock("@app/hooks", () => ({
11+
useAppConfig: () => ({
12+
appConfig: { galoyInstance: { name: "Main" } },
13+
}),
14+
useGoogleDriveBackup: () => ({
15+
startSession: mockStartSession,
16+
download: mockDownload,
17+
loading: false,
18+
}),
19+
}))
20+
21+
jest.mock("@app/config/appinfo", () => ({
22+
getSparkDriveBackupFilename: (name: string) => `spark-backup-${name}.json`,
23+
}))
24+
25+
jest.mock("@app/utils/spark-backup-format", () => ({
26+
parseBackupPayload: (content: string) => {
27+
const parsed = JSON.parse(content) as { mnemonic: string; encrypted?: boolean }
28+
if (parsed.encrypted) {
29+
throw new Error("Encrypted payload requires password")
30+
}
31+
return { mnemonic: parsed.mnemonic }
32+
},
33+
parseEncryptedBackupPayload: (content: string, _password: string) => {
34+
const parsed = JSON.parse(content) as { mnemonic: string }
35+
return { mnemonic: parsed.mnemonic }
36+
},
37+
}))
38+
39+
jest.mock("@app/screens/spark-onboarding/restore/hooks/use-restore-wallet", () => ({
40+
RestoreWalletStatus: { Idle: "idle", Restoring: "restoring", Error: "error" },
41+
useRestoreWallet: () => ({
42+
status: "idle",
43+
restore: mockRestore,
44+
}),
45+
}))
46+
47+
jest.mock("@react-native-firebase/crashlytics", () => () => ({
48+
recordError: (...args: Error[]) => mockRecordError(...args),
49+
}))
50+
51+
jest.mock("@app/i18n/i18n-react", () => ({
52+
useI18nContext: () => ({
53+
LL: {
54+
RestoreScreen: {
55+
wrongPassword: () => "Wrong password",
56+
},
57+
},
58+
}),
59+
}))
60+
61+
describe("useCloudRestore", () => {
62+
beforeEach(() => {
63+
jest.clearAllMocks()
64+
mockStartSession.mockResolvedValue({
65+
accessToken: "token",
66+
existingFileId: "file-id",
67+
})
68+
})
69+
70+
it("restores unencrypted backup automatically", async () => {
71+
mockDownload.mockResolvedValue({
72+
success: true,
73+
content: JSON.stringify({ mnemonic: "word1 word2 word3" }),
74+
})
75+
76+
renderHook(() => useCloudRestore())
77+
78+
await waitFor(() => {
79+
expect(mockRestore).toHaveBeenCalledWith("word1 word2 word3")
80+
})
81+
})
82+
83+
it("shows not-found when download fails", async () => {
84+
mockDownload.mockResolvedValue({
85+
success: false,
86+
error: "no-backup-found",
87+
})
88+
89+
const { result } = renderHook(() => useCloudRestore())
90+
91+
await waitFor(() => {
92+
expect(result.current.isNotFound).toBe(true)
93+
})
94+
})
95+
96+
it("shows password step for encrypted backup", async () => {
97+
mockDownload.mockResolvedValue({
98+
success: true,
99+
content: JSON.stringify({
100+
mnemonic: null,
101+
encrypted: true,
102+
data: "enc",
103+
iv: "iv",
104+
salt: "salt",
105+
}),
106+
})
107+
108+
const { result } = renderHook(() => useCloudRestore())
109+
110+
await waitFor(() => {
111+
expect(result.current.isPassword).toBe(true)
112+
})
113+
})
114+
115+
it("reports sign-in errors to crashlytics", async () => {
116+
mockStartSession.mockRejectedValue(new Error("sign-in failed"))
117+
118+
renderHook(() => useCloudRestore())
119+
120+
await waitFor(() => {
121+
expect(mockRecordError).toHaveBeenCalled()
122+
})
123+
})
124+
})

0 commit comments

Comments
 (0)