-
Notifications
You must be signed in to change notification settings - Fork 15
Test: Shared tests for start
#1032
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
0d9a056
feat: shared tests for 'start'
tuliomir 1913749
chore: removes duplicated tests
tuliomir aaf71b3
fix: move getAddressAtIndex loop to fullnode-specific tests
tuliomir 4d208c5
fix: remove unused imports from facade test
tuliomir 3450173
fix: linter
tuliomir 3e7a793
fix: integration tests
tuliomir 42f2525
refactor: factory pattern to describe.each
tuliomir 445702f
Merge branch 'master' into test/shared-start
tuliomir 940abf1
refactor: adapter names
tuliomir f554c7e
refactor: case insensitive validation
tuliomir 5682e8a
fix: error handling on facade tests
tuliomir 4ccfbe7
fix: linter
tuliomir 28fb85c
refactor: extract WalletTracker for safer wallet cleanup in tests
tuliomir 35b9dc9
test: add stop lifecycle tests for both wallet facades
tuliomir 1315075
Merge branch 'master' into test/shared-start
tuliomir dce7b80
Merge branch 'master' into test/shared-start
tuliomir 569e82d
refactor: extract stop options into shared constants in adapters
tuliomir 496887e
docs: clarify why injectFundsBeforeStart cannot use injectFunds
tuliomir 551fe24
docs: clarify resolveWalletData behavior for xpub/xpriv-only wallets
tuliomir 9ebed24
refactor: createWallet delegates to buildWalletInstance + startWallet
tuliomir 285b06f
refactor: method name clarifying
tuliomir b362c67
feat: add shared readonly (xpub) wallet start tests for both facades
tuliomir 4aa3ba7
refactor: extract deriveXpubFromSeed into shared utility
tuliomir e17dae2
fix: safer error handling and explicit address assertion
tuliomir 8e7a561
Merge branch 'master' into test/shared-start
tuliomir 903760f
Merge branch 'master' into test/shared-start
tuliomir File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,230 @@ | ||
| /* eslint-disable class-methods-use-this */ | ||
| /** | ||
| * Copyright (c) Hathor Labs and its affiliates. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
|
|
||
| import HathorWallet from '../../../src/new/wallet'; | ||
| import { WalletTracker } from '../utils/wallet-tracker.util'; | ||
| import { WalletState } from '../../../src/types'; | ||
| import type Transaction from '../../../src/models/transaction'; | ||
| import { | ||
| generateConnection, | ||
| waitForWalletReady, | ||
| waitForTxReceived, | ||
| waitUntilNextTimestamp, | ||
| DEFAULT_PASSWORD, | ||
| DEFAULT_PIN_CODE, | ||
| } from '../helpers/wallet.helper'; | ||
| import { GenesisWalletHelper } from '../helpers/genesis-wallet.helper'; | ||
| import { precalculationHelpers } from '../helpers/wallet-precalculation.helper'; | ||
| import type { WalletStopOptions } from '../../../src/new/types'; | ||
| import { NETWORK_NAME } from '../configuration/test-constants'; | ||
| import type { | ||
| FuzzyWalletType, | ||
| IWalletTestAdapter, | ||
| WalletCapabilities, | ||
| CreateWalletOptions, | ||
| CreateWalletResult, | ||
| } from './types'; | ||
| import type { PrecalculatedWalletData } from '../helpers/wallet-precalculation.helper'; | ||
|
|
||
| /** Stop options shared between {@link stopWallet} and the {@link WalletTracker}. */ | ||
| const STOP_OPTIONS: WalletStopOptions = { cleanStorage: true, cleanAddresses: true }; | ||
|
|
||
| /** | ||
| * Adapter for the fullnode facade ({@link HathorWallet}). | ||
| * | ||
| * Key behavioral differences from the service adapter: | ||
| * - `start()` returns immediately; callers must explicitly `waitForReady()`. | ||
| * - Supports multisig, xpub-readonly, token scoping, and external signing. | ||
| * - Uses the fullnode P2P helpers ({@link GenesisWalletHelper}) for fund injection. | ||
| */ | ||
| export class FullnodeWalletTestAdapter implements IWalletTestAdapter { | ||
| name = 'Fullnode'; | ||
|
|
||
| networkName = NETWORK_NAME; | ||
|
|
||
| defaultPinCode = DEFAULT_PIN_CODE; | ||
|
|
||
| defaultPassword = DEFAULT_PASSWORD; | ||
|
|
||
| capabilities: WalletCapabilities = { | ||
| supportsMultisig: true, | ||
| supportsTokenScope: true, | ||
| supportsXpubReadonly: true, | ||
| supportsExternalSigning: true, | ||
| supportsRuntimeAddressCalculation: true, | ||
| supportsPreStartFunding: true, | ||
| requiresExplicitWaitReady: true, | ||
| stateEventValues: { | ||
| loading: WalletState.CONNECTING, | ||
| ready: WalletState.READY, | ||
| }, | ||
| }; | ||
|
|
||
| private readonly tracker = new WalletTracker<HathorWallet>(STOP_OPTIONS); | ||
|
|
||
| /** | ||
| * Narrows a {@link FuzzyWalletType} to the concrete {@link HathorWallet}. | ||
| * | ||
| * The double-cast (`as unknown as`) is required because {@link IHathorWallet} | ||
| * and {@link HathorWallet} are not structurally compatible (see type aliases | ||
| * in types.ts). Centralizing it here keeps the rest of the adapter cast-free. | ||
| */ | ||
| private concrete(wallet: FuzzyWalletType): HathorWallet { | ||
| return wallet as unknown as HathorWallet; | ||
| } | ||
|
|
||
| async suiteSetup(): Promise<void> { | ||
| // GenesisWalletHelper lazily initializes via getSingleton(), no explicit setup needed. | ||
| await GenesisWalletHelper.getSingleton(); | ||
| } | ||
|
|
||
| async suiteTeardown(): Promise<void> { | ||
| await this.stopAllWallets(); | ||
| await GenesisWalletHelper.clearListeners(); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a fully started, ready-to-use wallet with default credentials. | ||
| * | ||
| * Delegates to {@link buildWalletInstance} for construction and | ||
| * {@link startWallet} for startup, filling in default credentials so tests | ||
| * that just need a working wallet have zero setup friction. | ||
| */ | ||
| async createWallet(options?: CreateWalletOptions): Promise<CreateWalletResult> { | ||
| const built = this.buildWalletInstance(options); | ||
|
|
||
| await this.startWallet(built.wallet, { | ||
| pinCode: options?.pinCode ?? DEFAULT_PIN_CODE, | ||
| password: options?.password ?? DEFAULT_PASSWORD, | ||
| }); | ||
| await this.waitForReady(built.wallet); | ||
|
|
||
| return built; | ||
| } | ||
|
|
||
| buildWalletInstance(options?: CreateWalletOptions): CreateWalletResult { | ||
| const walletData = this.resolveWordsAndAddresses(options); | ||
| const walletConfig = this.buildConfig(walletData, options); | ||
|
|
||
| const hWallet = new HathorWallet(walletConfig); | ||
| this.tracker.track(hWallet); | ||
|
|
||
| return { | ||
| wallet: hWallet as FuzzyWalletType, | ||
| storage: hWallet.storage, | ||
| words: walletData.words, | ||
| addresses: walletData.addresses, | ||
| }; | ||
| } | ||
|
|
||
| async startWallet( | ||
| wallet: FuzzyWalletType, | ||
| options?: { pinCode?: string; password?: string } | ||
| ): Promise<void> { | ||
| await this.concrete(wallet).start({ | ||
| pinCode: options?.pinCode, | ||
| password: options?.password, | ||
| }); | ||
| } | ||
|
|
||
| async waitForReady(wallet: FuzzyWalletType): Promise<void> { | ||
| await waitForWalletReady(this.concrete(wallet)); | ||
| } | ||
|
|
||
| async stopWallet(wallet: FuzzyWalletType): Promise<void> { | ||
| const hWallet = this.concrete(wallet); | ||
| await hWallet.stop(STOP_OPTIONS); | ||
| this.tracker.untrack(hWallet); | ||
| } | ||
|
|
||
| async stopAllWallets(): Promise<void> { | ||
| await this.tracker.stopAll(); | ||
| } | ||
|
|
||
| async injectFunds( | ||
| destWallet: FuzzyWalletType, | ||
| address: string, | ||
| amount: bigint | ||
| ): Promise<Transaction> { | ||
| return GenesisWalletHelper.injectFunds(this.concrete(destWallet), address, amount); | ||
| } | ||
|
|
||
| /** | ||
| * Sends funds to an address whose wallet has not started yet. | ||
| * | ||
| * Cannot delegate to {@link injectFunds} because that method polls both the | ||
| * genesis and the destination wallet for tx confirmation — but the destination | ||
| * wallet isn't running yet, so polling it would hang or fail. | ||
| */ | ||
| async injectFundsBeforeStart(address: string, amount: bigint): Promise<string> { | ||
| const { hWallet: gWallet } = await GenesisWalletHelper.getSingleton(); | ||
| const result = await gWallet.sendTransaction(address, amount); | ||
| if (!result || !result.hash) { | ||
| throw new Error('injectFundsBeforeStart: transaction had no hash'); | ||
| } | ||
| return result.hash; | ||
| } | ||
|
|
||
| async waitForTx(wallet: FuzzyWalletType, txId: string): Promise<void> { | ||
| const hWallet = this.concrete(wallet); | ||
| await waitForTxReceived(hWallet, txId); | ||
| await waitUntilNextTimestamp(hWallet, txId); | ||
| } | ||
|
|
||
| getPrecalculatedWallet(): PrecalculatedWalletData { | ||
| return precalculationHelpers.test!.getPrecalculatedWallet(); | ||
| } | ||
|
|
||
| // --- Private helpers --- | ||
|
|
||
| /** | ||
| * Resolves the wallet identity for simple cases (seed, addresses) from the caller's options. | ||
| * | ||
| * When no explicit identity is provided, a precalculated wallet is used. | ||
| * For xpub/xpriv-only wallets, `words` will be `undefined` — that's intentional: | ||
| * {@link buildConfig} spreads `xpub`/`xpriv` into the config independently of the seed. | ||
| */ | ||
| private resolveWordsAndAddresses(options?: CreateWalletOptions): { | ||
| words?: string; | ||
| addresses?: string[]; | ||
| } { | ||
| if (!options?.seed && !options?.xpub && !options?.xpriv) { | ||
| const precalc = this.getPrecalculatedWallet(); | ||
| return { words: precalc.words, addresses: precalc.addresses }; | ||
| } | ||
| return { | ||
| words: options?.seed, | ||
| addresses: options?.preCalculatedAddresses, | ||
| }; | ||
|
pedroferreira1 marked this conversation as resolved.
|
||
| } | ||
|
|
||
| private buildConfig( | ||
| walletData: { words?: string; addresses?: string[] }, | ||
| options?: CreateWalletOptions | ||
| ) { | ||
| // xpub/xpriv and seed are mutually exclusive in HathorWallet's constructor. | ||
| // When both are provided (e.g. shared readonly tests pass seed for service | ||
| // pre-registration), prefer xpub/xpriv and omit the seed. | ||
| const useSeed = !options?.xpub && !options?.xpriv; | ||
| return { | ||
| ...(useSeed && walletData.words ? { seed: walletData.words } : {}), | ||
| connection: generateConnection(), | ||
| // Credentials are intentionally omitted here — they are passed at start() | ||
| // time instead. This lets validation tests exercise missing-credential paths | ||
| // by calling buildWalletInstance + startWallet without defaults. | ||
| ...(options?.password !== undefined && { password: options.password }), | ||
| ...(options?.pinCode !== undefined && { pinCode: options.pinCode }), | ||
| preCalculatedAddresses: walletData.addresses, | ||
| ...(options?.xpub && { xpub: options.xpub }), | ||
| ...(options?.xpriv && { xpriv: options.xpriv }), | ||
| ...(options?.passphrase && { passphrase: options.passphrase }), | ||
| ...(options?.multisig && { multisig: options.multisig }), | ||
| ...(options?.tokenUid && { tokenUid: options.tokenUid }), | ||
| }; | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.