import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { find, render, settled, waitFor } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import Layer1TestWeb3Strategy from '@cardstack/web-client/utils/web3-strategies/test-layer1';
import Layer2TestWeb3Strategy from '@cardstack/web-client/utils/web3-strategies/test-layer2';
import { WorkflowSession } from '@cardstack/web-client/models/workflow';
import sinon from 'sinon';
import { currentNetworkDisplayInfo as c } from '@cardstack/web-client/utils/web3-strategies/network-display-info';
import { TransactionReceipt } from 'web3-core';
const depositSourceToken = 'DAI';
const stepTitles = {
deposit: `Deposit tokens into reserve pool on ${c.layer1.fullName}`,
bridge: `Bridge tokens from ${c.layer1.fullName} to ${c.layer2.fullName}`,
mint: `Mint tokens on ${c.layer2.shortName}: ${depositSourceToken}.CPXD`,
};
module(
'Integration | Component | card-pay/deposit-workflow/transaction-status',
function (hooks) {
setupRenderingTest(hooks);
test('it updates UI to display progress as bridging proceeds', async function (assert) {
let onComplete = sinon.spy();
let workflowSession = new WorkflowSession();
workflowSession.setValue({
depositSourceToken,
layer2BlockHeightBeforeBridging: '0',
relayTokensTxnReceipt: {
transactionHash: 'RelayTokensTransactionHash',
blockNumber: 1,
} as TransactionReceipt,
});
const layer1Service = this.owner.lookup('service:layer1-network')
.strategy as Layer1TestWeb3Strategy;
const layer2Service = this.owner.lookup('service:layer2-network')
.strategy as Layer2TestWeb3Strategy;
const blockCount = layer1Service.bridgeConfirmationBlockCount;
layer2Service.balancesRefreshed = false;
this.setProperties({
onComplete,
onIncomplete: () => {},
isComplete: false,
frozen: false,
workflowSession,
});
await render(hbs`
`);
assert.dom('[data-test-deposit-transaction-status-delay]').doesNotExist();
assert
.dom(`[data-test-token-bridge-step="0"][data-test-completed]`)
.containsText(stepTitles.deposit);
assert.dom(`[data-test-etherscan-button]`).exists();
assert
.dom(`[data-test-token-bridge-step][data-test-completed]`)
.exists({ count: 1 });
assert
.dom(`[data-test-token-bridge-step="1"]`)
.containsText(stepTitles.bridge);
assert
.dom(`[data-test-token-bridge-step-status="1"]`)
.hasText(`0 of ${blockCount} blocks confirmed`);
await settled();
let etherscanHref = find('[data-test-etherscan-button]')?.getAttribute(
'href'
)!;
assert
.dom('[data-test-deposit-transaction-status-delay] a')
.hasAttribute('href', etherscanHref);
layer1Service.test__simulateBlockConfirmation();
await waitFor(
`[data-test-token-bridge-step-block-count="${blockCount}"]`
);
assert
.dom(`[data-test-token-bridge-step-status="1"]`)
.hasText(`${blockCount} of ${blockCount} blocks confirmed`);
layer1Service.test__simulateBlockConfirmation();
await waitFor(
`[data-test-token-bridge-step-block-count="${blockCount + 1}"]`
);
assert
.dom(`[data-test-token-bridge-step-status="1"]`)
.hasText(`Waiting for bridge validators`);
layer1Service.test__simulateBlockConfirmation();
await waitFor(`[data-test-token-bridge-step="1"][data-test-completed]`);
assert.dom(`[data-test-bridge-explorer-button]`).exists();
assert
.dom(`[data-test-token-bridge-step="2"][data-test-completed]`)
.doesNotExist();
assert.dom(`[data-test-blockscout-button]`).doesNotExist();
let bridgeExplorerHerf = find(
'[data-test-bridge-explorer-button]'
)?.getAttribute('href')!;
assert
.dom('[data-test-deposit-transaction-status-delay] a')
.hasAttribute('href', bridgeExplorerHerf);
assert
.dom('[data-test-deposit-transaction-status-delay]')
.containsText(
'Due to network conditions this transaction is taking longer to confirm'
);
// bridging should also refresh layer 2 balances so we want to ensure that here
layer2Service.balancesRefreshed = false;
layer2Service.test__simulateBridgedToLayer2(
'CompletedLayer2TransactionHash'
);
await waitFor('[data-test-blockscout-button]');
assert.ok(
layer2Service.balancesRefreshed,
'Balances for layer 2 should be refreshsed after bridging'
);
assert
.dom(`[data-test-token-bridge-step="2"][data-test-completed]`)
.containsText(stepTitles.mint);
assert.dom('[data-test-blockscout-button]').exists();
assert.dom('[data-test-deposit-minting-step-failed]').doesNotExist();
assert.dom('[data-test-deposit-transaction-status-error]').doesNotExist();
assert.dom('[data-test-deposit-transaction-status-delay]').doesNotExist();
assert.ok(onComplete.called);
});
test('it displays all appropriate links and calls onComplete if it loads with appropriate data to complete the card', async function (assert) {
let onComplete = sinon.spy();
let workflowSession = new WorkflowSession();
workflowSession.setValue({
depositSourceToken,
layer2BlockHeightBeforeBridging: '0',
relayTokensTxnReceipt: {
transactionHash: 'RelayTokensTransactionHash',
blockNumber: 1,
} as TransactionReceipt,
completedLayer2TxnReceipt: {
transactionHash: 'CompletedLayer2TransactionHash',
blockNumber: 1,
} as TransactionReceipt,
});
this.setProperties({
onComplete,
onIncomplete: () => {},
isComplete: false,
frozen: false,
workflowSession,
});
await render(hbs`
`);
assert
.dom(`[data-test-token-bridge-step="0"][data-test-completed]`)
.containsText(stepTitles.deposit);
assert.dom(`[data-test-etherscan-button]`).exists();
assert
.dom(`[data-test-token-bridge-step="1"][data-test-completed]`)
.containsText(stepTitles.bridge);
assert.dom(`[data-test-bridge-explorer-button]`).exists();
assert
.dom(`[data-test-token-bridge-step="2"][data-test-completed]`)
.containsText(stepTitles.mint);
assert.dom('[data-test-blockscout-button]').exists();
assert.ok(onComplete.called);
});
test('it shows an error message if block confirmations fail', async function (assert) {
const layer1Service = this.owner.lookup('service:layer1-network')
.strategy as Layer1TestWeb3Strategy;
let onComplete = sinon.spy();
let workflowSession = new WorkflowSession();
workflowSession.setValue({
depositSourceToken,
layer2BlockHeightBeforeBridging: '0',
relayTokensTxnReceipt: {
transactionHash: 'RelayTokensTransactionHash',
blockNumber: 1,
} as TransactionReceipt,
});
sinon
.stub(layer1Service, 'getBlockConfirmation')
.throws(new Error('Block confirmation error'));
this.setProperties({
onComplete,
onIncomplete: () => {},
isComplete: false,
frozen: false,
workflowSession,
});
await render(hbs`
`);
assert.dom(`[data-test-etherscan-button]`).exists();
assert
.dom('[data-test-deposit-bridging-step-failed]')
.containsText('Failed');
assert
.dom('[data-test-deposit-transaction-status-error]')
.containsText(
`There was a problem completing the bridging of your tokens to ${c.layer2.fullName}. Please contact Cardstack support so that we can investigate and resolve this issue for you.`
);
assert.ok(onComplete.notCalled);
});
test('it shows an error message if bridging fails', async function (assert) {
const layer1Service = this.owner.lookup('service:layer1-network')
.strategy as Layer1TestWeb3Strategy;
const layer2Service = this.owner.lookup('service:layer2-network')
.strategy as Layer2TestWeb3Strategy;
const blockCount = layer1Service.bridgeConfirmationBlockCount;
let onComplete = sinon.spy();
let workflowSession = new WorkflowSession();
workflowSession.setValue({
depositSourceToken,
layer2BlockHeightBeforeBridging: '0',
relayTokensTxnReceipt: {
transactionHash: 'RelayTokensTransactionHash',
blockNumber: 1,
} as TransactionReceipt,
});
sinon
.stub(layer2Service, 'awaitBridgedToLayer2')
.throws(new Error('Bridging error'));
this.setProperties({
onComplete,
onIncomplete: () => {},
isComplete: false,
frozen: false,
workflowSession,
});
await render(hbs`
`);
layer1Service.test__simulateBlockConfirmation();
await waitFor(
`[data-test-token-bridge-step-block-count="${blockCount}"]`
);
layer1Service.test__simulateBlockConfirmation();
await waitFor(
`[data-test-token-bridge-step-block-count="${blockCount + 1}"]`
);
layer1Service.test__simulateBlockConfirmation();
await waitFor(`[data-test-token-bridge-step="1"][data-test-completed]`);
assert.dom(`[data-test-bridge-explorer-button]`).exists();
assert.dom(`[data-test-blockscout-button]`).doesNotExist();
assert
.dom('[data-test-deposit-minting-step-failed]')
.containsText('Failed');
assert
.dom('[data-test-deposit-transaction-status-error]')
.containsText(
`There was a problem completing the bridging of your tokens to ${c.layer2.fullName}. Please contact Cardstack support so that we can investigate and resolve this issue for you.`
);
assert.ok(onComplete.notCalled);
});
}
);