-
Notifications
You must be signed in to change notification settings - Fork 332
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Wallet Sync - Watch Loop Unit Tests (#7517)
support(live-wallet): Added unit tests to cover the createWalletSyncWatchLoop
- Loading branch information
1 parent
8fe8b24
commit 277648c
Showing
6 changed files
with
240 additions
and
25 deletions.
There are no files selected for viewing
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,5 @@ | ||
--- | ||
"@ledgerhq/live-wallet": patch | ||
--- | ||
|
||
LIVE-WALLET - Added unit tests to cover the createWalletSyncWatchLoop |
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
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
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,91 @@ | ||
import { CloudSyncSDKInterface } from "../../cloudsync"; | ||
import { z } from "zod"; | ||
import { Observable, never } from "rxjs"; | ||
import { WalletSyncDataManager } from "../types"; | ||
import { Trustchain, MemberCredentials } from "@ledgerhq/trustchain/types"; | ||
import { CreateWalletSyncWatchLoopParams } from "../createWalletSyncWatchLoop"; | ||
|
||
export const getWalletSyncWatchLoopConfig = () => { | ||
const schema = z.number(); | ||
type Data = number; | ||
|
||
const walletsync: WalletSyncDataManager<number, number, typeof schema> = { | ||
schema, | ||
diffLocalToDistant(local, latest) { | ||
return { hasChanges: local !== (latest || 0), nextState: local }; | ||
}, | ||
async resolveIncrementalUpdate(_ctx, local, latest, incoming) { | ||
if (incoming === latest || !incoming) { | ||
return { hasChanges: false }; | ||
} | ||
return { | ||
hasChanges: true, | ||
update: incoming, | ||
}; | ||
}, | ||
applyUpdate(_local, update) { | ||
return update; | ||
}, | ||
}; | ||
|
||
const trustchain = { | ||
rootId: "", | ||
applicationPath: "", | ||
walletSyncEncryptionKey: "", | ||
}; | ||
|
||
const memberCredentials = { | ||
pubkey: "", | ||
privatekey: "", | ||
}; | ||
|
||
const localIncrementUpdate = jest.fn(); | ||
|
||
const walletSyncSdk: CloudSyncSDKInterface<Data> = { | ||
pull: jest.fn().mockResolvedValue(undefined), | ||
push: jest.fn().mockResolvedValue(undefined), | ||
destroy: jest.fn().mockResolvedValue(undefined), | ||
listenNotifications( | ||
_trustchain: Trustchain, | ||
_memberCredentials: MemberCredentials, | ||
): Observable<number> { | ||
return never(); | ||
}, | ||
}; | ||
|
||
const getState = jest.fn().mockReturnValue(null); | ||
const localStateSelector = jest.fn().mockReturnValue(0); | ||
const latestDistantStateSelector = jest.fn().mockReturnValue(null); | ||
const onTrustchainRefreshNeeded = jest.fn(); | ||
|
||
const walletSyncWatchLoopConfig: CreateWalletSyncWatchLoopParams< | ||
number, | ||
number, | ||
number, | ||
typeof schema | ||
> = { | ||
walletsync, | ||
walletSyncSdk, | ||
trustchain, | ||
memberCredentials, | ||
getState, | ||
localStateSelector, | ||
latestDistantStateSelector, | ||
onTrustchainRefreshNeeded, | ||
localIncrementUpdate, | ||
}; | ||
|
||
return walletSyncWatchLoopConfig; | ||
}; | ||
|
||
/** | ||
* workaround on Jest advanceTimersByTime to awaits promises that arises inside setTimeouts | ||
* see https://stackoverflow.com/questions/51126786/jest-fake-timers-with-promises | ||
*/ | ||
export async function advanceTimersByTimeAsync(seconds: number) { | ||
const timeIncrement = 1000; | ||
for (let t = 0; t < 1000 * seconds; t += timeIncrement) { | ||
jest.advanceTimersByTime(timeIncrement); | ||
await Promise.resolve(); | ||
} | ||
} |
104 changes: 104 additions & 0 deletions
104
libs/live-wallet/src/walletsync/createWalletSyncWatchLoop.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,104 @@ | ||
import { createWalletSyncWatchLoop } from "./createWalletSyncWatchLoop"; | ||
import { advanceTimersByTimeAsync, getWalletSyncWatchLoopConfig } from "./__mocks__/watchLoop"; | ||
import { Subject } from "rxjs"; | ||
|
||
jest.useFakeTimers(); | ||
|
||
describe("createWalletSyncWatchLoop", () => { | ||
it("should pull but not push when there is no changes", async () => { | ||
const walletSyncWatchLoopConfig = getWalletSyncWatchLoopConfig(); | ||
|
||
const watchLoop = createWalletSyncWatchLoop(walletSyncWatchLoopConfig); | ||
|
||
await advanceTimersByTimeAsync(10); | ||
|
||
watchLoop.unsubscribe(); | ||
|
||
expect(walletSyncWatchLoopConfig.walletSyncSdk.pull).toHaveBeenCalledTimes(1); | ||
expect(walletSyncWatchLoopConfig.walletSyncSdk.push).toHaveBeenCalledTimes(0); | ||
}); | ||
|
||
it("should pull and push when there are changes", async () => { | ||
const walletSyncWatchLoopConfig = getWalletSyncWatchLoopConfig(); | ||
|
||
walletSyncWatchLoopConfig.latestDistantStateSelector = jest | ||
.fn() | ||
.mockReturnValueOnce(0) | ||
.mockReturnValue(1); | ||
walletSyncWatchLoopConfig.localStateSelector = jest.fn().mockReturnValue(1); | ||
|
||
const watchLoop = createWalletSyncWatchLoop(walletSyncWatchLoopConfig); | ||
|
||
await advanceTimersByTimeAsync(20); | ||
|
||
watchLoop.unsubscribe(); | ||
|
||
expect(walletSyncWatchLoopConfig.walletSyncSdk.pull).toHaveBeenCalledTimes(2); | ||
expect(walletSyncWatchLoopConfig.walletSyncSdk.pull).toHaveBeenCalledWith( | ||
walletSyncWatchLoopConfig.trustchain, | ||
walletSyncWatchLoopConfig.memberCredentials, | ||
); | ||
expect(walletSyncWatchLoopConfig.walletSyncSdk.push).toHaveBeenCalledTimes(1); | ||
expect(walletSyncWatchLoopConfig.walletSyncSdk.push).toHaveBeenCalledWith( | ||
walletSyncWatchLoopConfig.trustchain, | ||
walletSyncWatchLoopConfig.memberCredentials, | ||
1, | ||
); | ||
}); | ||
|
||
it("notifications triggers the watch loop", async () => { | ||
const walletSyncWatchLoopConfig = getWalletSyncWatchLoopConfig(); | ||
|
||
const notifications = new Subject<number>(); | ||
|
||
walletSyncWatchLoopConfig.walletSyncSdk.listenNotifications = (t, m) => { | ||
expect(t).toEqual(walletSyncWatchLoopConfig.trustchain); | ||
expect(m).toEqual(walletSyncWatchLoopConfig.memberCredentials); | ||
return notifications; | ||
}; | ||
|
||
walletSyncWatchLoopConfig.watchConfig = { | ||
notificationsEnabled: true, | ||
initialTimeout: 5000, | ||
pollingInterval: 10000, | ||
}; | ||
|
||
const watchLoop = createWalletSyncWatchLoop(walletSyncWatchLoopConfig); | ||
|
||
await advanceTimersByTimeAsync(15); | ||
expect(walletSyncWatchLoopConfig.walletSyncSdk.pull).toHaveBeenCalledTimes(2); | ||
|
||
notifications.next(2); | ||
|
||
await advanceTimersByTimeAsync(1); | ||
expect(walletSyncWatchLoopConfig.walletSyncSdk.pull).toHaveBeenCalledTimes(3); | ||
|
||
watchLoop.unsubscribe(); | ||
}); | ||
|
||
it("notifications disabled does not triggers the watch loop", async () => { | ||
const walletSyncWatchLoopConfig = getWalletSyncWatchLoopConfig(); | ||
|
||
const notifications = new Subject<number>(); | ||
|
||
walletSyncWatchLoopConfig.walletSyncSdk.listenNotifications = () => notifications; | ||
|
||
walletSyncWatchLoopConfig.watchConfig = { | ||
notificationsEnabled: false, | ||
initialTimeout: 5000, | ||
pollingInterval: 10000, | ||
}; | ||
|
||
const watchLoop = createWalletSyncWatchLoop(walletSyncWatchLoopConfig); | ||
|
||
await advanceTimersByTimeAsync(15); | ||
expect(walletSyncWatchLoopConfig.walletSyncSdk.pull).toHaveBeenCalledTimes(2); | ||
|
||
notifications.next(2); | ||
|
||
await advanceTimersByTimeAsync(1); | ||
expect(walletSyncWatchLoopConfig.walletSyncSdk.pull).toHaveBeenCalledTimes(2); | ||
|
||
watchLoop.unsubscribe(); | ||
}); | ||
}); |
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