import algosdk, { Address } from 'algosdk'; import { TransactionLogger } from '../testing'; import { TestLogger } from '../testing/test-logger'; import { AlgoAmount } from '../types/amount'; import { MultisigAccount, SigningAccount, TransactionSignerAccount } from './account'; import { AlgorandClient } from './algorand-client'; import { AlgoConfig } from './network-client'; import Account = algosdk.Account; import Algodv2 = algosdk.Algodv2; import Indexer = algosdk.Indexer; import Kmd = algosdk.Kmd; import LogicSigAccount = algosdk.LogicSigAccount; import Transaction = algosdk.Transaction; /** * Test automation context. */ export interface AlgorandTestAutomationContext { /** An AlgorandClient instance loaded with the current context, including testAccount and any generated accounts loaded as signers */ algorand: AlgorandClient; /** Algod client instance that will log transactions in `transactionLogger` */ algod: Algodv2; /** Indexer client instance */ indexer: Indexer; /** KMD client instance */ kmd: Kmd; /** Transaction logger that will log transaction IDs for all transactions issued by `algod` */ transactionLogger: TransactionLogger; /** Default, funded test account that is ephemerally created */ testAccount: Address & TransactionSignerAccount & Account; /** Generate and fund an additional ephemerally created account */ generateAccount: (params: GetTestAccountParams) => Promise
; /** Wait for the indexer to catch up with all transactions logged by `transactionLogger` */ waitForIndexer: () => Promise; /** Wait for the indexer to catch up with the given transaction ID */ waitForIndexerTransaction: (transactionId: string) => Promise; } /** * Parameters for the `getTestAccount` function. */ export interface GetTestAccountParams { /** Initial funds to ensure the account has */ initialFunds: AlgoAmount; /** Whether to suppress the log (which includes a mnemonic) or not (default: do not suppress the log) */ suppressLog?: boolean; /** Optional override for how to get a test account; this allows you to retrieve accounts from a known or cached list of accounts. */ accountGetter?: (algorand: AlgorandClient) => Promise; } /** Configuration for creating an Algorand testing fixture. */ export interface AlgorandFixtureConfig extends Partial { /** An optional algod client, if not specified then it will create one against `algodConfig` (if present) then environment variables defined network (if present) or default LocalNet. */ algod?: Algodv2; /** An optional indexer client, if not specified then it will create one against `indexerConfig` (if present) then environment variables defined network (if present) or default LocalNet. */ indexer?: Indexer; /** An optional kmd client, if not specified then it will create one against `kmdConfig` (if present) then environment variables defined network (if present) or default LocalNet. */ kmd?: Kmd; /** The amount of funds to allocate to the default testing account, if not specified then it will get 10 ALGO. */ testAccountFunding?: AlgoAmount; /** Optional override for how to get an account; this allows you to retrieve accounts from a known or cached list of accounts. */ accountGetter?: (algod: Algodv2, kmd?: Kmd) => Promise; } /** An Algorand automated testing fixture */ export interface AlgorandFixture { /** * Retrieve the current context. * Useful with destructuring. * * If you haven't called `newScope` then this will throw an error. * @example * ```typescript * test('My test', () => { * const {algod, indexer, testAccount, ...} = fixture.context * }) * ``` */ get context(): AlgorandTestAutomationContext; /** * Retrieve an `AlgorandClient` loaded with the current context, including testAccount and any generated accounts loaded as signers. */ get algorand(): AlgorandClient; /** * @deprecated Use newScope instead. * Testing framework agnostic handler method to run before each test to prepare the `context` for that test with per test isolation. */ beforeEach: () => Promise; /** * Creates a new isolated fixture scope (clean transaction logger, AlgorandClient, testAccount, etc.). * * You can call this from any testing framework specific hook method to control when you want a new scope. * * @example Jest / vitest - per test isolation (beforeEach) * ```typescript * describe('MY MODULE', () => { * const fixture = algorandFixture() * beforeEach(fixture.newScope) * * test('MY TEST', async () => { * const { algorand, testAccount } = fixture.context * * // Test stuff! * }) * }) * ``` * * @example Jest / vitest - test suite isolation (beforeAll) * ```typescript * describe('MY MODULE', () => { * const fixture = algorandFixture() * beforeAll(fixture.newScope) * * test('test1', async () => { * const { algorand, testAccount } = fixture.context * * // Test stuff! * }) * test('test2', async () => { * const { algorand, testAccount } = fixture.context * // algorand and testAccount are the same as in test1 * }) * }) * ``` * */ newScope: () => Promise; } /** Configuration for preparing a captured log snapshot. * This helps ensure that the provided configuration items won't appear * with random values in the log snapshot, but rather will get substituted with predictable ids. */ export interface LogSnapshotConfig { /** Any transaction IDs or transactions to replace the ID for predictably */ transactions?: (string | Transaction)[]; /** Any accounts/addresses to replace the address for predictably */ accounts?: (string | Address | Account | SigningAccount | LogicSigAccount | MultisigAccount | TransactionSignerAccount)[]; /** Any app IDs to replace predictably */ apps?: (string | number | bigint)[]; /** Optional filter predicate to filter out logs */ filterPredicate?: (log: string) => boolean; } export interface AlgoKitLogCaptureFixture { /** The test logger instance for the current test */ get testLogger(): TestLogger; /** * Testing framework agnostic handler method to run before each test to prepare the `testLogger` for that test. */ beforeEach: () => void; /** * Testing framework agnostic handler method to run after each test to reset the logger. */ afterEach: () => void; }