UNPKG

@ledgerhq/coin-tester

Version:
115 lines 6.61 kB
import chalk from "chalk"; import { first, firstValueFrom, map, reduce } from "rxjs"; import { DeviceModelId } from "@ledgerhq/types-devices"; export async function executeScenario(scenario, strategy = "legacy") { try { const { accountBridge, currencyBridge, account, retryInterval, retryLimit, onSignerConfirmation, } = await scenario.setup(strategy); console.log("Setup completed ✓"); console.log("\n"); console.log(chalk.bgBlue(" Address "), " → ", chalk.bold.blue(account.freshAddress), "\n\n"); const data = await currencyBridge.preload(account.currency); currencyBridge.hydrate(data, account.currency); console.log("Preload + hydrate completed ✓"); await scenario.beforeSync?.(); console.log("Running a synchronization on the account..."); let scenarioAccount = await firstValueFrom(accountBridge .sync(account, { paginationConfig: {} }) .pipe(reduce((acc, f) => f(acc), account))); console.log("Synchronization completed ✓"); await scenario.beforeAll?.(scenarioAccount); console.log("BeforeAll completed ✓"); console.log("\n\n"); console.log(chalk.bgCyan.black.bold(" ✧ "), " ", chalk.cyan(`Scenario: ${chalk.italic.bold(scenario.name)}`), " ", chalk.bgCyan.black.bold(" ✧ "), " → ", chalk.bold.cyan(" Starting ◌")); const scenarioTransactions = scenario.getTransactions(account.freshAddress); for (const testTransaction of scenarioTransactions) { console.log("\n"); console.log(chalk.cyan("Transaction:", chalk.bold(testTransaction.name), "◌")); await scenario.beforeEach?.(scenarioAccount); console.log("Before each ✔️"); if (scenarioTransactions.indexOf(testTransaction) > 0) { await scenario.beforeSync?.(); scenarioAccount = await firstValueFrom(accountBridge .sync(scenarioAccount, { paginationConfig: {} }) .pipe(reduce((acc, f) => f(acc), scenarioAccount))); } const previousAccount = Object.freeze(scenarioAccount); const defaultTransaction = accountBridge.createTransaction(scenarioAccount); const transaction = await accountBridge.prepareTransaction(scenarioAccount, { ...defaultTransaction, ...testTransaction, }); console.log(" → ", "🧑‍🍳 ", chalk.bold("Prepared the transaction"), "✓"); const status = await accountBridge.getTransactionStatus(scenarioAccount, transaction); if (Object.entries(status.errors).length) { throw new Error(`${testTransaction.name} transaction\nError in transaction status: ${JSON.stringify(status.errors, null, 3)}`); } console.log(" → ", "🪲 ", chalk.bold("No status errors detected"), "✓"); const { signedOperation } = await firstValueFrom(accountBridge .signOperation({ account: scenarioAccount, transaction, deviceId: "", deviceModelId: DeviceModelId.nanoX, // TODO: use "test" once test signatures from the CAL // are all compatible with Speculos public key certificateSignatureKind: "prod", }) .pipe(map(e => { if (e.type === "device-signature-requested") { onSignerConfirmation?.(e); } return e; }), first((e) => e.type === "signed"))); console.log(" → ", "🔏 ", chalk.bold("Signed the transaction"), "✓"); const optimisticOperation = await accountBridge.broadcast({ signedOperation, account: scenarioAccount, }); console.log(" → ", "🛫 ", chalk.bold("Broadcasted the transaction"), "✓"); const retry_limit = retryLimit ?? 10; async function expectHandler(retry) { await scenario.beforeSync?.(); scenarioAccount = await firstValueFrom(accountBridge .sync({ ...scenarioAccount, pendingOperations: [optimisticOperation] }, { paginationConfig: {} }) .pipe(reduce((acc, f) => f(acc), scenarioAccount))); if (!testTransaction.expect) { console.warn(chalk.yellow(`No expects in the transaction ${chalk.bold(testTransaction.name)}. You might want to add tests in this transaction.`)); return; } try { testTransaction.expect?.(previousAccount, scenarioAccount); } catch (err) { if (!err?.matcherResult?.pass) { if (retry === 0) { console.error(chalk.red(`Retried ${retry_limit} time(s) and could not assert all expects for transaction ${chalk.bold(testTransaction.name)}`)); throw err; } console.warn(chalk.magenta("Test asssertion failed. Retrying...")); await new Promise(resolve => setTimeout(resolve, retryInterval ?? 3 * 1000)); await expectHandler(retry - 1); } else { throw err; } } } await scenario.mockIndexer?.(scenarioAccount, optimisticOperation); await expectHandler(retry_limit); await scenario.afterEach?.(scenarioAccount); console.log("After each ✔️"); console.log(chalk.green("Transaction:", chalk.bold(testTransaction.name), "completed ✓")); } console.log("\n"); await scenario.afterAll?.(scenarioAccount); console.log("afterAll completed ✓"); await scenario.teardown?.(); console.log("\n\n", chalk.bgGreen.black.bold(" ✧ "), " ", chalk.green(`Scenario: ${chalk.italic.bold(scenario.name)}`), " ", chalk.bgGreen.black.bold(" ✧ "), " → ", chalk.bold.green(" Completed 🎉"), "\n\n"); } catch (err) { console.error("\n\n", chalk.bgRed.black.bold(" ✧ "), " ", chalk.red(`Scenario: ${chalk.italic.bold(scenario.name)}`), " ", chalk.bgRed.black.bold(" ✧ "), " → ", chalk.bold.red(" Failed ❌"), "\n\n"); await scenario.teardown?.(); throw err; } } //# sourceMappingURL=main.js.map