import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { click, render } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import { toWei } from 'web3-utils'; import BN from 'bn.js'; import Layer2TestWeb3Strategy from '@cardstack/web-client/utils/web3-strategies/test-layer2'; import { WorkflowSession } from '@cardstack/web-client/models/workflow'; import { setupMirage } from 'ember-cli-mirage/test-support'; import { MirageTestContext } from 'ember-cli-mirage/test-support'; import { createDepotSafe, createMerchantSafe, createPrepaidCardSafe, createSafeToken, } from '@cardstack/web-client/utils/test-factories'; import { DepotSafe, MerchantSafe } from '@cardstack/cardpay-sdk'; import { faceValueOptions } from '@cardstack/web-client/components/card-pay/issue-prepaid-card-workflow'; interface Context extends MirageTestContext {} const MIN_SPEND_AMOUNT = Math.min(...faceValueOptions); const MIN_AMOUNT_TO_PASS = new BN( toWei(`${Math.ceil(MIN_SPEND_AMOUNT / 100)}`) ); module( 'Integration | Component | card-pay/issue-prepaid-card-workflow/funding-source', function (hooks) { let layer2Service: Layer2TestWeb3Strategy; let layer2AccountAddress = '0x182619c6Ea074C053eF3f1e1eF81Ec8De6Eb6E44'; let depotSafe: DepotSafe; let merchantSafe: MerchantSafe; let workflowSession: WorkflowSession; setupRenderingTest(hooks); setupMirage(hooks); module('when there is a depot safe', function (hooks) { hooks.beforeEach(async function (this: Context) { layer2Service = this.owner.lookup('service:layer2-network') .strategy as Layer2TestWeb3Strategy; depotSafe = createDepotSafe({ owners: [layer2AccountAddress], tokens: [ createSafeToken('DAI.CPXD', '125000000000000000000'), createSafeToken('CARD.CPXD', '450000000000000000000'), ], }); merchantSafe = createMerchantSafe({ address: '0xmerchantbAB0644ffCD32518eBF4924ba8666666', merchant: '0xprepaidDbAB0644ffCD32518eBF4924ba8666666', tokens: [ createSafeToken('DAI.CPXD', MIN_AMOUNT_TO_PASS.toString()), createSafeToken('CARD.CPXD', '450000000000000000000'), ], accumulatedSpendValue: 100, }); layer2Service.test__simulateRemoteAccountSafes(layer2AccountAddress, [ depotSafe, merchantSafe, createMerchantSafe({ address: 'low-balance-safe', merchant: '0xprepaidDbAB0644ffCD32518eBF4924ba8666666', tokens: [createSafeToken('DAI.CPXD', '1')], accumulatedSpendValue: 100, }), createPrepaidCardSafe({ address: '0xprepaidDbAB0644ffCD32518eBF4924ba8666666', owners: [layer2AccountAddress], tokens: [ createSafeToken('DAI.CPXD', '125000000000000000000'), createSafeToken('CARD.CPXD', '450000000000000000000'), ], spendFaceValue: 2324, prepaidCardOwner: layer2AccountAddress, issuer: layer2AccountAddress, transferrable: false, }), ]); layer2Service.test__simulateAccountsChanged([layer2AccountAddress]); workflowSession = new WorkflowSession(); workflowSession.setValue('daiMinValue', MIN_AMOUNT_TO_PASS); this.setProperties({ onComplete: () => {}, onIncomplete: () => {}, isComplete: false, frozen: false, workflowSession, }); }); test('it defaults to the depot safe when one has not been set in the workflow', async function (assert) { await render(hbs` `); assert.dom('[data-test-funding-source-safe]').containsText('DEPOT'); }); test('it falls back to the first safe with a sufficient balance if the depot safe has insufficient balance', async function (assert) { depotSafe.tokens = [createSafeToken('DAI.CPXD', '1')]; layer2Service.test__simulateAccountsChanged([layer2AccountAddress]); await render(hbs` `); assert .dom('[data-test-funding-source-safe]') .containsText('Business account'); }); test('it uses the safe from the workflow when it exists', async function (this: Context, assert) { workflowSession.setValue( 'prepaidFundingSafeAddress', merchantSafe.address ); await render(hbs` `); assert .dom('[data-test-funding-source-safe]') .containsText('Business account'); }); test('it only lists compatible safes with balances of compatible tokens that exceed the minimum in the workflow', async function (this: Context, assert) { await render(hbs` `); await click( '[data-test-safe-chooser-dropdown] .ember-power-select-trigger' ); assert.dom('.ember-power-select-options li').exists({ count: 2 }); }); test('it renders an error message when no safe with sufficient balances exists', async function (assert) { depotSafe.tokens = [createSafeToken('DAI.CPXD', '1')]; merchantSafe.tokens = [createSafeToken('DAI.CPXD', '1')]; layer2Service.test__simulateAccountsChanged([layer2AccountAddress]); await render(hbs` `); assert .dom('[data-test-insufficient-balance-message]') .containsText('5 DAI.CPXD'); assert.dom('[data-test-boxel-button]').isDisabled(); }); }); test('it renders the proper fallback balance when there is no depot safe', async function (assert) { layer2Service = this.owner.lookup('service:layer2-network') .strategy as Layer2TestWeb3Strategy; merchantSafe = createMerchantSafe({ address: '0xmerchantbAB0644ffCD32518eBF4924ba8666666', merchant: '0xprepaidDbAB0644ffCD32518eBF4924ba8666666', tokens: [ createSafeToken('DAI.CPXD', MIN_AMOUNT_TO_PASS.toString()), createSafeToken('CARD.CPXD', '450000000000000000000'), ], accumulatedSpendValue: 100, }); layer2Service.test__simulateRemoteAccountSafes(layer2AccountAddress, [ merchantSafe, ]); layer2Service.test__simulateAccountsChanged([layer2AccountAddress]); workflowSession = new WorkflowSession(); workflowSession.setValue('daiMinValue', MIN_AMOUNT_TO_PASS); this.setProperties({ onComplete: () => {}, onIncomplete: () => {}, isComplete: false, frozen: false, workflowSession, }); await render(hbs` `); assert .dom('[data-test-balance-chooser-dropdown]') .containsText('5.00 DAI.CPXD'); }); } );