Skip to content

Commit

Permalink
feat: Add transaction flow and details sections (#27654)
Browse files Browse the repository at this point in the history
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Adds two new sections for the wallet initiated ERC20 token transfer
redesigned confirmation.

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27654?quickstart=1)

## **Related issues**

Fixes: MetaMask/MetaMask-planning#3220

## **Manual testing steps**

1. Go to this page...
2.
3.

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

<img width="368" alt="Screenshot 2024-10-07 at 11 04 58"
src="https://github.com/user-attachments/assets/3e160876-be5c-46d2-b03a-b841f93b08d1">


## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
pedronfigueiredo authored Oct 17, 2024
1 parent f58d598 commit dc48117
Show file tree
Hide file tree
Showing 36 changed files with 1,200 additions and 207 deletions.
3 changes: 3 additions & 0 deletions app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Driver } from '../../../../webdriver/driver';
import { RawLocator } from '../../../common';

class WatchAssetConfirmation {
private driver: Driver;

private footerConfirmButton: RawLocator;

constructor(driver: Driver) {
this.driver = driver;

this.footerConfirmButton = '[data-testid="page-container-footer-next"]';
}

async clickFooterConfirmButton() {
await this.driver.clickElement(this.footerConfirmButton);
}
}

export default WatchAssetConfirmation;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Driver } from '../../webdriver/driver';
import { RawLocator } from '../common';
import { Driver } from '../../../../webdriver/driver';
import { RawLocator } from '../../../common';

class Confirmation {
protected driver: Driver;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { tEn } from '../../../lib/i18n-helpers';
import { Driver } from '../../webdriver/driver';
import { RawLocator } from '../common';
import { tEn } from '../../../../../lib/i18n-helpers';
import { Driver } from '../../../../webdriver/driver';
import { RawLocator } from '../../../common';
import TransactionConfirmation from './transaction-confirmation';

class SetApprovalForAllTransactionConfirmation extends TransactionConfirmation {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { tEn } from '../../../../../lib/i18n-helpers';
import { Driver } from '../../../../webdriver/driver';
import { RawLocator } from '../../../common';
import TransactionConfirmation from './transaction-confirmation';

class TokenTransferTransactionConfirmation extends TransactionConfirmation {
private networkParagraph: RawLocator;

private interactingWithParagraph: RawLocator;

private networkFeeParagraph: RawLocator;

constructor(driver: Driver) {
super(driver);

this.driver = driver;

this.networkParagraph = {
css: 'p',
text: tEn('transactionFlowNetwork') as string,
};
this.interactingWithParagraph = {
css: 'p',
text: tEn('interactingWith') as string,
};
this.networkFeeParagraph = {
css: 'p',
text: tEn('networkFee') as string,
};
}

async check_networkParagraph() {
await this.driver.waitForSelector(this.networkParagraph);
}

async check_interactingWithParagraph() {
await this.driver.waitForSelector(this.interactingWithParagraph);
}

async check_networkFeeParagraph() {
await this.driver.waitForSelector(this.networkFeeParagraph);
}
}

export default TokenTransferTransactionConfirmation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { tEn } from '../../../../../lib/i18n-helpers';
import { Driver } from '../../../../webdriver/driver';
import { RawLocator } from '../../../common';
import Confirmation from './confirmation';

class TransactionConfirmation extends Confirmation {
private walletInitiatedHeadingTitle: RawLocator;

constructor(driver: Driver) {
super(driver);

this.driver = driver;

this.walletInitiatedHeadingTitle = {
css: 'h3',
text: tEn('review') as string,
};
}

async check_walletInitiatedHeadingTitle() {
await this.driver.waitForSelector(this.walletInitiatedHeadingTitle);
}
}

export default TransactionConfirmation;
16 changes: 16 additions & 0 deletions test/e2e/page-objects/pages/send/send-token-page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { strict as assert } from 'assert';
import { Driver } from '../../../webdriver/driver';
import { RawLocator } from '../../common';

class SendTokenPage {
private driver: Driver;
Expand All @@ -18,6 +19,10 @@ class SendTokenPage {

private ensResolvedAddress: string;

private assetPickerButton: RawLocator;

private tokenListButton: RawLocator;

constructor(driver: Driver) {
this.driver = driver;
this.inputAmount = '[data-testid="currency-input"]';
Expand All @@ -32,6 +37,8 @@ class SendTokenPage {
text: 'Continue',
tag: 'button',
};
this.assetPickerButton = '[data-testid="asset-picker-button"]';
this.tokenListButton = '[data-testid="multichain-token-list-button"]';
}

async check_pageIsLoaded(): Promise<void> {
Expand Down Expand Up @@ -125,6 +132,15 @@ class SendTokenPage {
`ENS domain '${ensDomain}' resolved to address '${address}' and can be used as recipient on send token screen.`,
);
}

async click_assetPickerButton() {
await this.driver.clickElement(this.assetPickerButton);
}

async click_secondTokenListButton() {
const elements = await this.driver.findElements(this.tokenListButton);
await elements[1].click();
}
}

export default SendTokenPage;
15 changes: 14 additions & 1 deletion test/e2e/page-objects/pages/test-dapp.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Driver } from '../../webdriver/driver';
import { WINDOW_TITLES } from '../../helpers';
import { Driver } from '../../webdriver/driver';
import { RawLocator } from '../common';

const DAPP_HOST_ADDRESS = '127.0.0.1:8080';
const DAPP_URL = `http://${DAPP_HOST_ADDRESS}`;
Expand Down Expand Up @@ -83,8 +84,16 @@ class TestDapp {

private readonly signTypedDataVerifyResult = '#signTypedDataVerifyResult';

private erc20WatchAssetButton: RawLocator;

constructor(driver: Driver) {
this.driver = driver;

this.erc721SetApprovalForAllButton = '#setApprovalForAllButton';
this.erc1155SetApprovalForAllButton = '#setApprovalForAllERC1155Button';
this.erc721RevokeSetApprovalForAllButton = '#revokeButton';
this.erc1155RevokeSetApprovalForAllButton = '#revokeERC1155Button';
this.erc20WatchAssetButton = '#watchAssets';
}

async check_pageIsLoaded(): Promise<void> {
Expand Down Expand Up @@ -143,6 +152,10 @@ class TestDapp {
await this.driver.clickElement(this.erc1155RevokeSetApprovalForAllButton);
}

public async clickERC20WatchAssetButton() {
await this.driver.clickElement(this.erc20WatchAssetButton);
}

/**
* Verify the failed personal sign signature.
*
Expand Down
5 changes: 0 additions & 5 deletions test/e2e/page-objects/pages/transaction-confirmation.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { TransactionEnvelopeType } from '@metamask/transaction-controller';
import { DAPP_URL } from '../../../constants';
import { unlockWallet, WINDOW_TITLES } from '../../../helpers';
import { Mockttp } from '../../../mock-e2e';
import SetApprovalForAllTransactionConfirmation from '../../../page-objects/pages/set-approval-for-all-transaction-confirmation';
import SetApprovalForAllTransactionConfirmation from '../../../page-objects/pages/confirmations/redesign/set-approval-for-all-transaction-confirmation';
import TestDapp from '../../../page-objects/pages/test-dapp';
import GanacheContractAddressRegistry from '../../../seeder/ganache-contract-address-registry';
import { Driver } from '../../../webdriver/driver';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { TransactionEnvelopeType } from '@metamask/transaction-controller';
import { DAPP_URL, unlockWallet, WINDOW_TITLES } from '../../../helpers';
import { Mockttp } from '../../../mock-e2e';
import SetApprovalForAllTransactionConfirmation from '../../../page-objects/pages/set-approval-for-all-transaction-confirmation';
import SetApprovalForAllTransactionConfirmation from '../../../page-objects/pages/confirmations/redesign/set-approval-for-all-transaction-confirmation';
import TestDapp from '../../../page-objects/pages/test-dapp';
import GanacheContractAddressRegistry from '../../../seeder/ganache-contract-address-registry';
import { Driver } from '../../../webdriver/driver';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */
import { TransactionEnvelopeType } from '@metamask/transaction-controller';
import { DAPP_URL } from '../../../constants';
import { unlockWallet, WINDOW_TITLES } from '../../../helpers';
import { Mockttp } from '../../../mock-e2e';
import WatchAssetConfirmation from '../../../page-objects/pages/confirmations/legacy/watch-asset-confirmation';
import TokenTransferTransactionConfirmation from '../../../page-objects/pages/confirmations/redesign/token-transfer-confirmation';
import HomePage from '../../../page-objects/pages/homepage';
import SendTokenPage from '../../../page-objects/pages/send/send-token-page';
import TestDapp from '../../../page-objects/pages/test-dapp';
import GanacheContractAddressRegistry from '../../../seeder/ganache-contract-address-registry';
import { Driver } from '../../../webdriver/driver';
import { withRedesignConfirmationFixtures } from '../helpers';
import { TestSuiteArguments } from './shared';

const { SMART_CONTRACTS } = require('../../../seeder/smart-contracts');

describe('Confirmation Redesign ERC20 Token Send @no-mmi', function () {
it('Sends a type 0 transaction (Legacy)', async function () {
await withRedesignConfirmationFixtures(
this.test?.fullTitle(),
TransactionEnvelopeType.legacy,
async ({ driver, contractRegistry }: TestSuiteArguments) => {
await createTransactionAndAssertDetails(driver, contractRegistry);
},
mocks,
SMART_CONTRACTS.HST,
);
});

it('Sends a type 2 transaction (EIP1559)', async function () {
await withRedesignConfirmationFixtures(
this.test?.fullTitle(),
TransactionEnvelopeType.feeMarket,
async ({ driver, contractRegistry }: TestSuiteArguments) => {
await createTransactionAndAssertDetails(driver, contractRegistry);
},
mocks,
SMART_CONTRACTS.HST,
);
});
});

async function mocks(server: Mockttp) {
return [await mockedSourcifyTokenSend(server)];
}

export async function mockedSourcifyTokenSend(mockServer: Mockttp) {
return await mockServer
.forGet('https://www.4byte.directory/api/v1/signatures/')
.withQuery({ hex_signature: '0xa9059cbb' })
.always()
.thenCallback(() => ({
statusCode: 200,
json: {
count: 1,
next: null,
previous: null,
results: [
{
bytes_signature: '©\u0005œ»',
created_at: '2016-07-09T03:58:28.234977Z',
hex_signature: '0xa9059cbb',
id: 145,
text_signature: 'transfer(address,uint256)',
},
],
},
}));
}

async function createTransactionAndAssertDetails(
driver: Driver,
contractRegistry?: GanacheContractAddressRegistry,
) {
await unlockWallet(driver);

const contractAddress = await (
contractRegistry as GanacheContractAddressRegistry
).getContractAddress(SMART_CONTRACTS.HST);

const testDapp = new TestDapp(driver);

await testDapp.openTestDappPage({ contractAddress, url: DAPP_URL });

await testDapp.clickERC20WatchAssetButton();

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const watchAssetConfirmation = new WatchAssetConfirmation(driver);
await watchAssetConfirmation.clickFooterConfirmButton();

await driver.switchToWindowWithTitle(WINDOW_TITLES.ExtensionInFullScreenView);

const homePage = new HomePage(driver);
await homePage.startSendFlow();

const sendToPage = new SendTokenPage(driver);
await sendToPage.check_pageIsLoaded();
await sendToPage.fillRecipient('0x2f318C334780961FB129D2a6c30D0763d9a5C970');
await sendToPage.fillAmount('1');

await sendToPage.click_assetPickerButton();
await sendToPage.click_secondTokenListButton();
await sendToPage.goToNextScreen();

const tokenTransferTransactionConfirmation =
new TokenTransferTransactionConfirmation(driver);
await tokenTransferTransactionConfirmation.check_walletInitiatedHeadingTitle();
await tokenTransferTransactionConfirmation.check_networkParagraph();
await tokenTransferTransactionConfirmation.check_interactingWithParagraph();
await tokenTransferTransactionConfirmation.check_networkFeeParagraph();

await tokenTransferTransactionConfirmation.clickFooterConfirmButton();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { TransactionEnvelopeType } from '@metamask/transaction-controller';
import { DAPP_URL } from '../../../constants';
import { unlockWallet, WINDOW_TITLES } from '../../../helpers';
import { Mockttp } from '../../../mock-e2e';
import SetApprovalForAllTransactionConfirmation from '../../../page-objects/pages/set-approval-for-all-transaction-confirmation';
import SetApprovalForAllTransactionConfirmation from '../../../page-objects/pages/confirmations/redesign/set-approval-for-all-transaction-confirmation';
import TestDapp from '../../../page-objects/pages/test-dapp';
import GanacheContractAddressRegistry from '../../../seeder/ganache-contract-address-registry';
import { Driver } from '../../../webdriver/driver';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { TransactionEnvelopeType } from '@metamask/transaction-controller';
import { DAPP_URL, unlockWallet, WINDOW_TITLES } from '../../../helpers';
import { Mockttp } from '../../../mock-e2e';
import SetApprovalForAllTransactionConfirmation from '../../../page-objects/pages/set-approval-for-all-transaction-confirmation';
import SetApprovalForAllTransactionConfirmation from '../../../page-objects/pages/confirmations/redesign/set-approval-for-all-transaction-confirmation';
import TestDapp from '../../../page-objects/pages/test-dapp';
import GanacheContractAddressRegistry from '../../../seeder/ganache-contract-address-registry';
import { Driver } from '../../../webdriver/driver';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import {
TransactionType,
} from '@metamask/transaction-controller';
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { useConfirmContext } from '../../../../context/confirm';
import { useAssetDetails } from '../../../../hooks/useAssetDetails';
import { selectConfirmationAdvancedDetailsOpen } from '../../../../selectors/preferences';
import { AdvancedDetails } from '../shared/advanced-details/advanced-details';
import { ConfirmLoader } from '../shared/confirm-loader/confirm-loader';
import { GasFeesSection } from '../shared/gas-fees-section/gas-fees-section';
Expand All @@ -24,10 +22,6 @@ const ApproveInfo = () => {
currentConfirmation: TransactionMeta;
};

const showAdvancedDetails = useSelector(
selectConfirmationAdvancedDetailsOpen,
);

const { isNFT } = useIsNFT(transactionMeta);

const [isOpenEditSpendingCapModal, setIsOpenEditSpendingCapModal] =
Expand Down Expand Up @@ -70,7 +64,7 @@ const ApproveInfo = () => {
/>
)}
<GasFeesSection />
{showAdvancedDetails && <AdvancedDetails />}
<AdvancedDetails />
<EditSpendingCapModal
isOpenEditSpendingCapModal={isOpenEditSpendingCapModal}
setIsOpenEditSpendingCapModal={setIsOpenEditSpendingCapModal}
Expand Down
Loading

0 comments on commit dc48117

Please sign in to comment.