diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index bd1ebb7f0de8..5853e94ea661 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -3770,6 +3770,9 @@ "permissionDetails": { "message": "Permission details" }, + "permissionFor": { + "message": "Permission for" + }, "permissionRequest": { "message": "Permission request" }, @@ -4733,6 +4736,9 @@ "setApprovalForAll": { "message": "Set approval for all" }, + "setApprovalForAllRedesignedTitle": { + "message": "Withdrawal request" + }, "setApprovalForAllTitle": { "message": "Approve $1 with no spend limit", "description": "The token symbol that is being approved" @@ -4852,6 +4858,9 @@ "simulationDetailsOutgoingHeading": { "message": "You send" }, + "simulationDetailsSetApprovalForAllDesc": { + "message": "You're giving permission for someone else to withdraw NFTs from your account." + }, "simulationDetailsTitle": { "message": "Estimated changes" }, @@ -6536,6 +6545,9 @@ "whatsThis": { "message": "What's this?" }, + "withdrawing": { + "message": "Withdrawing" + }, "wrongNetworkName": { "message": "According to our records, the network name may not correctly match this chain ID." }, diff --git a/app/_locales/en_GB/messages.json b/app/_locales/en_GB/messages.json index e67b9f0e4fcb..dd89cd804f75 100644 --- a/app/_locales/en_GB/messages.json +++ b/app/_locales/en_GB/messages.json @@ -6458,9 +6458,6 @@ "whatsThis": { "message": "What's this?" }, - "wrongChainId": { - "message": "This chain ID doesn’t match the network name." - }, "wrongNetworkName": { "message": "According to our records, the network name may not correctly match this chain ID." }, diff --git a/sonar-project.properties b/sonar-project.properties index 31d4a98b41e7..0ee619db70ff 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,8 +2,9 @@ sonar.projectKey=metamask-extension sonar.organization=consensys # Source -sonar.sources=app,development,offscreen,shared,test,types,ui -sonar.exclusions=**/*.test.**,**/*.spec.**,app/images,test/** +sonar.sources=app,development,offscreen,shared,types,ui +sonar.exclusions=**/*.test.**,**/*.spec.**,app/images,test/e2e/page-objects,test/data + # Tests sonar.tests=app,development,offscreen,shared,test,types,ui diff --git a/test/data/confirmations/contract-interaction.ts b/test/data/confirmations/contract-interaction.ts index f6ad5a8633ea..0556789ccdb2 100644 --- a/test/data/confirmations/contract-interaction.ts +++ b/test/data/confirmations/contract-interaction.ts @@ -181,3 +181,23 @@ export const genUnapprovedApproveConfirmation = ({ }, type: TransactionType.tokenMethodApprove, }); + +export const genUnapprovedSetApprovalForAllConfirmation = ({ + address = CONTRACT_INTERACTION_SENDER_ADDRESS, + chainId = CHAIN_ID, +}: { + address?: Hex; + chainId?: string; +} = {}) => ({ + ...genUnapprovedContractInteractionConfirmation({ chainId }), + txParams: { + from: address, + data: '0x095ea7b30000000000000000000000002e0d7e8c45221fca00d74a3609a0f7097035d09b0000000000000000000000000000000000000000000000000000000000000001', + gas: '0x16a92', + to: '0x076146c765189d51be3160a2140cf80bfc73ad68', + value: '0x0', + maxFeePerGas: '0x5b06b0c0d', + maxPriorityFeePerGas: '0x59682f00', + }, + type: TransactionType.tokenMethodSetApprovalForAll, +}); diff --git a/test/data/confirmations/helper.ts b/test/data/confirmations/helper.ts index c542ee92feab..9eb8bb234768 100644 --- a/test/data/confirmations/helper.ts +++ b/test/data/confirmations/helper.ts @@ -10,6 +10,7 @@ import { CHAIN_IDS } from '../../../shared/constants/network'; import { genUnapprovedApproveConfirmation, genUnapprovedContractInteractionConfirmation, + genUnapprovedSetApprovalForAllConfirmation, } from './contract-interaction'; import { unapprovedPersonalSignMsg } from './personal_sign'; import { unapprovedTypedSignMsgV4 } from './typed_sign'; @@ -176,3 +177,9 @@ export const getMockApproveConfirmState = () => { genUnapprovedApproveConfirmation({ chainId: '0x5' }), ); }; + +export const getMockSetApprovalForAllConfirmState = () => { + return getMockConfirmStateForTransaction( + genUnapprovedSetApprovalForAllConfirmation({ chainId: '0x5' }), + ); +}; diff --git a/test/e2e/page-objects/common.ts b/test/e2e/page-objects/common.ts new file mode 100644 index 000000000000..b1f678b80cca --- /dev/null +++ b/test/e2e/page-objects/common.ts @@ -0,0 +1 @@ +export type RawLocator = string | { css: string; text: string }; diff --git a/test/e2e/page-objects/pages/confirmation.ts b/test/e2e/page-objects/pages/confirmation.ts new file mode 100644 index 000000000000..3ec372cb3163 --- /dev/null +++ b/test/e2e/page-objects/pages/confirmation.ts @@ -0,0 +1,27 @@ +import { Driver } from '../../webdriver/driver'; +import { RawLocator } from '../common'; + +class Confirmation { + protected driver: Driver; + + private scrollToBottomButton: RawLocator; + + private footerConfirmButton: RawLocator; + + constructor(driver: Driver) { + this.driver = driver; + + this.scrollToBottomButton = '.confirm-scroll-to-bottom__button'; + this.footerConfirmButton = '[data-testid="confirm-footer-button"]'; + } + + async clickScrollToBottomButton() { + await this.driver.clickElementSafe(this.scrollToBottomButton); + } + + async clickFooterConfirmButton() { + await this.driver.clickElement(this.footerConfirmButton); + } +} + +export default Confirmation; diff --git a/test/e2e/page-objects/pages/set-approval-for-all-transaction-confirmation.ts b/test/e2e/page-objects/pages/set-approval-for-all-transaction-confirmation.ts new file mode 100644 index 000000000000..ddd6ccb5e2b8 --- /dev/null +++ b/test/e2e/page-objects/pages/set-approval-for-all-transaction-confirmation.ts @@ -0,0 +1,35 @@ +import { tEn } from '../../../lib/i18n-helpers'; +import { Driver } from '../../webdriver/driver'; +import { RawLocator } from '../common'; +import TransactionConfirmation from './transaction-confirmation'; + +class SetApprovalForAllTransactionConfirmation extends TransactionConfirmation { + private setApprovalForAllTitleElement: RawLocator; + + private setApprovalForAllSubHeadingElement: RawLocator; + + constructor(driver: Driver) { + super(driver); + + this.driver = driver; + + this.setApprovalForAllTitleElement = { + css: 'h2', + text: tEn('setApprovalForAllRedesignedTitle') as string, + }; + this.setApprovalForAllSubHeadingElement = { + css: 'p', + text: tEn('confirmTitleDescApproveTransaction') as string, + }; + } + + async check_setApprovalForAllTitle() { + await this.driver.waitForSelector(this.setApprovalForAllTitleElement); + } + + async check_setApprovalForAllSubHeading() { + await this.driver.waitForSelector(this.setApprovalForAllSubHeadingElement); + } +} + +export default SetApprovalForAllTransactionConfirmation; diff --git a/test/e2e/page-objects/pages/test-dapp.ts b/test/e2e/page-objects/pages/test-dapp.ts index 8c2fe513ca10..29ff1f1e16b7 100644 --- a/test/e2e/page-objects/pages/test-dapp.ts +++ b/test/e2e/page-objects/pages/test-dapp.ts @@ -1,4 +1,5 @@ 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}`; @@ -6,8 +7,15 @@ const DAPP_URL = `http://${DAPP_HOST_ADDRESS}`; class TestDapp { private driver: Driver; + private erc721SetApprovalForAllButton: RawLocator; + + private erc1155SetApprovalForAllButton: RawLocator; + constructor(driver: Driver) { this.driver = driver; + + this.erc721SetApprovalForAllButton = '#setApprovalForAllButton'; + this.erc1155SetApprovalForAllButton = '#setApprovalForAllERC1155Button'; } async open({ @@ -32,6 +40,14 @@ class TestDapp { )}`, }); } + + async clickERC721SetApprovalForAllButton() { + await this.driver.clickElement(this.erc721SetApprovalForAllButton); + } + + async clickERC1155SetApprovalForAllButton() { + await this.driver.clickElement(this.erc1155SetApprovalForAllButton); + } } export default TestDapp; diff --git a/test/e2e/page-objects/pages/transaction-confirmation.ts b/test/e2e/page-objects/pages/transaction-confirmation.ts new file mode 100644 index 000000000000..7ae98d74d4c8 --- /dev/null +++ b/test/e2e/page-objects/pages/transaction-confirmation.ts @@ -0,0 +1,5 @@ +import Confirmation from './confirmation'; + +class TransactionConfirmation extends Confirmation {} + +export default TransactionConfirmation; diff --git a/test/e2e/tests/confirmations/helpers.ts b/test/e2e/tests/confirmations/helpers.ts index 7fe5ef9da87b..ff467f42c320 100644 --- a/test/e2e/tests/confirmations/helpers.ts +++ b/test/e2e/tests/confirmations/helpers.ts @@ -1,6 +1,12 @@ +import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import FixtureBuilder from '../../fixture-builder'; -import { defaultGanacheOptions, withFixtures } from '../../helpers'; +import { + defaultGanacheOptions, + defaultGanacheOptionsForType2Transactions, + withFixtures, +} from '../../helpers'; import { MockedEndpoint, Mockttp } from '../../mock-e2e'; +import { SMART_CONTRACTS } from '../../seeder/smart-contracts'; import { Driver } from '../../webdriver/driver'; export async function scrollAndConfirmAndAssertConfirm(driver: Driver) { @@ -14,15 +20,15 @@ export function withRedesignConfirmationFixtures( // title. It's optional because it's sometimes unset. // eslint-disable-next-line @typescript-eslint/default-param-last title: string = '', + transactionEnvelopeType: TransactionEnvelopeType, testFunction: Parameters[1], - mockSegment?: (mockServer: Mockttp) => Promise, // Add mockSegment as an optional parameter + mocks?: (mockServer: Mockttp) => Promise, // Add mocks as an optional parameter + smartContract?: typeof SMART_CONTRACTS, ) { return withFixtures( { dapp: true, - driverOptions: { - timeOut: 20000, - }, + driverOptions: { timeOut: 20000 }, fixtures: new FixtureBuilder() .withPermissionControllerConnectedToTestDapp() .withMetaMetricsController({ @@ -32,12 +38,17 @@ export function withRedesignConfirmationFixtures( .withPreferencesController({ preferences: { redesignedConfirmationsEnabled: true, + isRedesignedConfirmationsDeveloperEnabled: true, }, }) .build(), - ganacheOptions: defaultGanacheOptions, + ganacheOptions: + transactionEnvelopeType === TransactionEnvelopeType.legacy + ? defaultGanacheOptions + : defaultGanacheOptionsForType2Transactions, + smartContract, + testSpecificMock: mocks, title, - testSpecificMock: mockSegment, }, testFunction, ); diff --git a/test/e2e/tests/confirmations/navigation.spec.ts b/test/e2e/tests/confirmations/navigation.spec.ts index f6347981ce15..8d195656dc44 100644 --- a/test/e2e/tests/confirmations/navigation.spec.ts +++ b/test/e2e/tests/confirmations/navigation.spec.ts @@ -1,11 +1,12 @@ import { strict as assert } from 'assert'; +import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { Suite } from 'mocha'; import { DAPP_HOST_ADDRESS, WINDOW_TITLES, openDapp, - unlockWallet, regularDelayMs, + unlockWallet, } from '../../helpers'; import { Driver } from '../../webdriver/driver'; import { withRedesignConfirmationFixtures } from './helpers'; @@ -14,6 +15,7 @@ describe('Navigation Signature - Different signature types', function (this: Sui it('initiates and queues multiple signatures and confirms', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver }: { driver: Driver }) => { await unlockWallet(driver); await openDapp(driver); @@ -53,6 +55,7 @@ describe('Navigation Signature - Different signature types', function (this: Sui it('initiates and queues a mix of signatures and transactions and navigates', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver }: { driver: Driver }) => { await unlockWallet(driver); await openDapp(driver); @@ -90,6 +93,7 @@ describe('Navigation Signature - Different signature types', function (this: Sui it('initiates multiple signatures and rejects all', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver }: { driver: Driver }) => { await unlockWallet(driver); await openDapp(driver); diff --git a/test/e2e/tests/confirmations/signatures/malicious-signatures.spec.ts b/test/e2e/tests/confirmations/signatures/malicious-signatures.spec.ts index 7e4568d326f0..bde56537e43f 100644 --- a/test/e2e/tests/confirmations/signatures/malicious-signatures.spec.ts +++ b/test/e2e/tests/confirmations/signatures/malicious-signatures.spec.ts @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; +import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { Suite } from 'mocha'; import { MockedEndpoint } from 'mockttp'; import { WINDOW_TITLES } from '../../../helpers'; @@ -19,6 +20,7 @@ describe('Malicious Confirmation Signature - Bad Domain @no-mmi', function (this it('displays alert for domain binding and confirms', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver }: TestSuiteArguments) => { await openDappAndTriggerSignature(driver, SignatureType.SIWE_BadDomain); @@ -41,6 +43,7 @@ describe('Malicious Confirmation Signature - Bad Domain @no-mmi', function (this it('initiates and rejects from confirmation screen', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, mockedEndpoint: mockedEndpoints, @@ -87,6 +90,7 @@ describe('Malicious Confirmation Signature - Bad Domain @no-mmi', function (this it('initiates and rejects from alert friction modal', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, mockedEndpoint: mockedEndpoints, diff --git a/test/e2e/tests/confirmations/signatures/permit.spec.ts b/test/e2e/tests/confirmations/signatures/permit.spec.ts index 8455a9fa8254..cd27f359aa87 100644 --- a/test/e2e/tests/confirmations/signatures/permit.spec.ts +++ b/test/e2e/tests/confirmations/signatures/permit.spec.ts @@ -1,11 +1,12 @@ import { strict as assert } from 'assert'; +import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { Suite } from 'mocha'; import { MockedEndpoint } from 'mockttp'; import { DAPP_HOST_ADDRESS, - WINDOW_TITLES, openDapp, unlockWallet, + WINDOW_TITLES, } from '../../../helpers'; import { Ganache } from '../../../seeder/ganache'; import { Driver } from '../../../webdriver/driver'; @@ -32,6 +33,7 @@ describe('Confirmation Signature - Permit @no-mmi', function (this: Suite) { it('initiates and confirms and emits the correct events', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, ganacheServer, @@ -75,6 +77,7 @@ describe('Confirmation Signature - Permit @no-mmi', function (this: Suite) { it('initiates and rejects and emits the correct events', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, mockedEndpoint: mockedEndpoints, diff --git a/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts b/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts index 31adfc9b4212..429881bf2f23 100644 --- a/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts +++ b/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; +import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { Suite } from 'mocha'; import { MockedEndpoint } from 'mockttp'; import { DAPP_HOST_ADDRESS, WINDOW_TITLES } from '../../../helpers'; @@ -26,6 +27,7 @@ describe('Confirmation Signature - Personal Sign @no-mmi', function (this: Suite it('initiates and confirms', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, ganacheServer, @@ -65,6 +67,7 @@ describe('Confirmation Signature - Personal Sign @no-mmi', function (this: Suite it('initiates and rejects', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, mockedEndpoint: mockedEndpoints, diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts index 43e30f3b60c0..0eb1d2c698b1 100644 --- a/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; +import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { Suite } from 'mocha'; import { MockedEndpoint } from 'mockttp'; import { DAPP_HOST_ADDRESS, WINDOW_TITLES } from '../../../helpers'; @@ -27,6 +28,7 @@ describe('Confirmation Signature - Sign Typed Data V3 @no-mmi', function (this: it('initiates and confirms', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, ganacheServer, @@ -69,6 +71,7 @@ describe('Confirmation Signature - Sign Typed Data V3 @no-mmi', function (this: it('initiates and rejects', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, mockedEndpoint: mockedEndpoints, diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts index 98311553d463..d78acb511ce9 100644 --- a/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; +import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { Suite } from 'mocha'; import { MockedEndpoint } from 'mockttp'; import { DAPP_HOST_ADDRESS, WINDOW_TITLES } from '../../../helpers'; @@ -27,6 +28,7 @@ describe('Confirmation Signature - Sign Typed Data V4 @no-mmi', function (this: it('initiates and confirms', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, ganacheServer, @@ -75,6 +77,7 @@ describe('Confirmation Signature - Sign Typed Data V4 @no-mmi', function (this: it('initiates and rejects', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, mockedEndpoint: mockedEndpoints, diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts index b76a4cfef70b..358d6b112cfc 100644 --- a/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; +import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { Suite } from 'mocha'; import { MockedEndpoint } from 'mockttp'; import { DAPP_HOST_ADDRESS, WINDOW_TITLES } from '../../../helpers'; @@ -26,6 +27,7 @@ describe('Confirmation Signature - Sign Typed Data @no-mmi', function (this: Sui it('initiates and confirms', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, ganacheServer, @@ -67,6 +69,7 @@ describe('Confirmation Signature - Sign Typed Data @no-mmi', function (this: Sui it('initiates and rejects', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, mockedEndpoint: mockedEndpoints, diff --git a/test/e2e/tests/confirmations/signatures/siwe.spec.ts b/test/e2e/tests/confirmations/signatures/siwe.spec.ts index da1ce9bcde27..edc3a2020862 100644 --- a/test/e2e/tests/confirmations/signatures/siwe.spec.ts +++ b/test/e2e/tests/confirmations/signatures/siwe.spec.ts @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; +import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { Suite } from 'mocha'; import { MockedEndpoint } from 'mockttp'; import { DAPP_HOST_ADDRESS, WINDOW_TITLES } from '../../../helpers'; @@ -26,6 +27,7 @@ describe('Confirmation Signature - SIWE @no-mmi', function (this: Suite) { it('initiates and confirms', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, mockedEndpoint: mockedEndpoints, @@ -68,6 +70,7 @@ describe('Confirmation Signature - SIWE @no-mmi', function (this: Suite) { it('initiates and rejects', async function () { await withRedesignConfirmationFixtures( this.test?.fullTitle(), + TransactionEnvelopeType.legacy, async ({ driver, mockedEndpoint: mockedEndpoints, diff --git a/test/e2e/tests/confirmations/transactions/erc1155-set-approval-for-all-redesign.spec.ts b/test/e2e/tests/confirmations/transactions/erc1155-set-approval-for-all-redesign.spec.ts new file mode 100644 index 000000000000..7d87cab123b3 --- /dev/null +++ b/test/e2e/tests/confirmations/transactions/erc1155-set-approval-for-all-redesign.spec.ts @@ -0,0 +1,101 @@ +/* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +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 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 ERC1155 setApprovalForAll', function () { + describe('Submit a transaction @no-mmi', function () { + it('Sends a type 0 transaction (Legacy)', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + TransactionEnvelopeType.legacy, + async ({ driver, contractRegistry }: TestSuiteArguments) => { + await createTransactionAssertDetailsAndConfirm( + driver, + contractRegistry, + ); + }, + mocks, + SMART_CONTRACTS.NFTS, + ); + }); + + it('Sends a type 2 transaction (EIP1559)', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + TransactionEnvelopeType.feeMarket, + async ({ driver, contractRegistry }: TestSuiteArguments) => { + await createTransactionAssertDetailsAndConfirm( + driver, + contractRegistry, + ); + }, + mocks, + SMART_CONTRACTS.NFTS, + ); + }); + }); +}); + +async function mocks(server: Mockttp) { + return [await mocked4BytesSetApprovalForAll(server)]; +} + +export async function mocked4BytesSetApprovalForAll(mockServer: Mockttp) { + return await mockServer + .forGet('https://www.4byte.directory/api/v1/signatures/') + .withQuery({ hex_signature: '0xa22cb465' }) + .always() + .thenCallback(() => ({ + statusCode: 200, + json: { + count: 1, + next: null, + previous: null, + results: [ + { + bytes_signature: '¢,´e', + created_at: '2018-04-11T21:47:39.980645Z', + hex_signature: '0xa22cb465', + id: 29659, + text_signature: 'setApprovalForAll(address,bool)', + }, + ], + }, + })); +} + +async function createTransactionAssertDetailsAndConfirm( + driver: Driver, + contractRegistry?: GanacheContractAddressRegistry, +) { + await unlockWallet(driver); + + const contractAddress = await ( + contractRegistry as GanacheContractAddressRegistry + ).getContractAddress(SMART_CONTRACTS.NFTS); + + const testDapp = new TestDapp(driver); + + await testDapp.open({ contractAddress, url: DAPP_URL }); + await testDapp.clickERC1155SetApprovalForAllButton(); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + const setApprovalForAllConfirmation = + new SetApprovalForAllTransactionConfirmation(driver); + + await setApprovalForAllConfirmation.check_setApprovalForAllTitle(); + await setApprovalForAllConfirmation.check_setApprovalForAllSubHeading(); + + await setApprovalForAllConfirmation.clickScrollToBottomButton(); + await setApprovalForAllConfirmation.clickFooterConfirmButton(); +} diff --git a/test/e2e/tests/confirmations/transactions/erc721-set-approval-for-all-redesign.spec.ts b/test/e2e/tests/confirmations/transactions/erc721-set-approval-for-all-redesign.spec.ts new file mode 100644 index 000000000000..7ca9518cabc2 --- /dev/null +++ b/test/e2e/tests/confirmations/transactions/erc721-set-approval-for-all-redesign.spec.ts @@ -0,0 +1,101 @@ +/* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +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 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 ERC721 setApprovalForAll', function () { + describe('Submit a transaction @no-mmi', function () { + it('Sends a type 0 transaction (Legacy)', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + TransactionEnvelopeType.legacy, + async ({ driver, contractRegistry }: TestSuiteArguments) => { + await createTransactionAssertDetailsAndConfirm( + driver, + contractRegistry, + ); + }, + mocks, + SMART_CONTRACTS.NFTS, + ); + }); + + it('Sends a type 2 transaction (EIP1559)', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + TransactionEnvelopeType.feeMarket, + async ({ driver, contractRegistry }: TestSuiteArguments) => { + await createTransactionAssertDetailsAndConfirm( + driver, + contractRegistry, + ); + }, + mocks, + SMART_CONTRACTS.NFTS, + ); + }); + }); +}); + +async function mocks(server: Mockttp) { + return [await mocked4BytesSetApprovalForAll(server)]; +} + +export async function mocked4BytesSetApprovalForAll(mockServer: Mockttp) { + return await mockServer + .forGet('https://www.4byte.directory/api/v1/signatures/') + .withQuery({ hex_signature: '0xa22cb465' }) + .always() + .thenCallback(() => ({ + statusCode: 200, + json: { + count: 1, + next: null, + previous: null, + results: [ + { + bytes_signature: '¢,´e', + created_at: '2018-04-11T21:47:39.980645Z', + hex_signature: '0xa22cb465', + id: 29659, + text_signature: 'setApprovalForAll(address,bool)', + }, + ], + }, + })); +} + +async function createTransactionAssertDetailsAndConfirm( + driver: Driver, + contractRegistry?: GanacheContractAddressRegistry, +) { + await unlockWallet(driver); + + const contractAddress = await ( + contractRegistry as GanacheContractAddressRegistry + ).getContractAddress(SMART_CONTRACTS.NFTS); + + const testDapp = new TestDapp(driver); + + await testDapp.open({ contractAddress, url: DAPP_URL }); + await testDapp.clickERC721SetApprovalForAllButton(); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + const setApprovalForAllConfirmation = + new SetApprovalForAllTransactionConfirmation(driver); + + await setApprovalForAllConfirmation.check_setApprovalForAllTitle(); + await setApprovalForAllConfirmation.check_setApprovalForAllSubHeading(); + + await setApprovalForAllConfirmation.clickScrollToBottomButton(); + await setApprovalForAllConfirmation.clickFooterConfirmButton(); +} diff --git a/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap index 3c4163f80950..93ff5170e172 100644 --- a/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap @@ -1,5 +1,612 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Info renders info section for approve request 1`] = ` +
+
+
+
+

+ Data +

+
+
+ + + + + + + + + +
+
+
+
+
+
+
+

+ Data +

+
+
+ + + + + + + + + +
+
+
+
+
+

+ Request from +

+
+
+ +
+
+
+
+

+ metamask.github.io +

+
+
+
+
+
+
+

+ Network fee +

+
+
+ +
+
+
+
+

+ 0.0001 ETH +

+

+ $0.04 +

+ +
+
+
+
+

+ Speed +

+
+
+
+

+ 🦊 Market +

+

+ + ~ + 0 sec + +

+
+
+
+
+
+`; + +exports[`Info renders info section for contract interaction request 1`] = ` +
+
+
+
+
+

+ Estimated changes +

+
+
+ +
+
+
+
+ + + + + + + + + +
+
+
+
+
+
+
+

+ Request from +

+
+
+ +
+
+
+
+

+ metamask.github.io +

+
+
+
+
+

+ Interacting with +

+
+
+ +
+
+
+
+
+ +

+ 0x88AA6...A5125 +

+
+
+
+
+
+
+
+

+ Network fee +

+
+
+ +
+
+
+
+

+ 0.0001 ETH +

+

+ $0.04 +

+ +
+
+
+
+

+ Speed +

+
+
+
+

+ 🦊 Market +

+

+ + ~ + 0 sec + +

+
+
+
+
+
+`; + exports[`Info renders info section for personal sign request 1`] = `
`; +exports[`Info renders info section for setApprovalForAll request 1`] = ` +
+
+
+
+

+ Estimated changes +

+
+
+ +
+
+
+
+

+ You're giving permission for someone else to withdraw NFTs from your account. +

+
+
+
+
+

+ Withdrawing +

+
+
+
+
+

+ All +

+
+
+
+ +

+ 0x07614...3ad68 +

+
+
+
+
+
+
+
+
+
+
+

+ Data +

+
+
+ + + + + + + + + +
+
+
+
+
+

+ Request from +

+
+
+ +
+
+
+
+

+ metamask.github.io +

+
+
+
+
+
+
+

+ Network fee +

+
+
+ +
+
+
+
+

+ 0.0001 ETH +

+

+ $0.04 +

+ +
+
+
+
+

+ Speed +

+
+
+
+

+ 🦊 Market +

+

+ + ~ + 0 sec + +

+
+
+
+
+
+`; + exports[`Info renders info section for typed sign request 1`] = `
renders component for approve details 1`] = `
`; + +exports[` renders component for approve details for setApprovalForAll 1`] = ` +
+
+
+
+
+

+ Data +

+
+
+ + + + + + + + + +
+
+
+
+
+`; diff --git a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.test.tsx b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.test.tsx index 72c4f62d4adb..daec14c166af 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.test.tsx @@ -17,4 +17,14 @@ describe('', () => { ); expect(container).toMatchSnapshot(); }); + + it('renders component for approve details for setApprovalForAll', () => { + const state = mockState; + const mockStore = configureMockStore(middleware)(state); + const { container } = renderWithConfirmContextProvider( + , + mockStore, + ); + expect(container).toMatchSnapshot(); + }); }); diff --git a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx index 6c38842e8e39..57d8903994bb 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx @@ -19,7 +19,11 @@ import { } from '../../shared/transaction-details/transaction-details'; import { useIsNFT } from '../hooks/use-is-nft'; -const Spender = () => { +const Spender = ({ + isSetApprovalForAll = false, +}: { + isSetApprovalForAll?: boolean; +}) => { const t = useI18nContext(); const { currentConfirmation: transactionMeta } = @@ -44,7 +48,7 @@ const Spender = () => { return ( <> { ); }; -export const ApproveDetails = () => { +export const ApproveDetails = ({ + isSetApprovalForAll = false, +}: { + isSetApprovalForAll?: boolean; +}) => { const showAdvancedDetails = useSelector( selectConfirmationAdvancedDetailsOpen, ); return ( - + {showAdvancedDetails && ( <> diff --git a/ui/pages/confirmations/components/confirm/info/info.test.tsx b/ui/pages/confirmations/components/confirm/info/info.test.tsx index f2c0a232259a..4931c2fbaa01 100644 --- a/ui/pages/confirmations/components/confirm/info/info.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/info.test.tsx @@ -2,7 +2,10 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import { + getMockApproveConfirmState, + getMockContractInteractionConfirmState, getMockPersonalSignConfirmState, + getMockSetApprovalForAllConfirmState, getMockTypedSignConfirmState, } from '../../../../../../test/data/confirmations/helper'; import { renderWithConfirmContextProvider } from '../../../../../../test/lib/confirmations/render-helpers'; @@ -17,6 +20,14 @@ jest.mock( }), ); +jest.mock('../../../../../store/actions', () => ({ + ...jest.requireActual('../../../../../store/actions'), + getGasFeeTimeEstimate: jest.fn().mockResolvedValue({ + lowerTimeBound: 0, + upperTimeBound: 60000, + }), +})); + describe('Info', () => { it('renders info section for personal sign request', () => { const state = getMockPersonalSignConfirmState(); @@ -31,4 +42,25 @@ describe('Info', () => { const { container } = renderWithConfirmContextProvider(, mockStore); expect(container).toMatchSnapshot(); }); + + it('renders info section for contract interaction request', () => { + const state = getMockContractInteractionConfirmState(); + const mockStore = configureMockStore([])(state); + const { container } = renderWithConfirmContextProvider(, mockStore); + expect(container).toMatchSnapshot(); + }); + + it('renders info section for approve request', () => { + const state = getMockApproveConfirmState(); + const mockStore = configureMockStore([])(state); + const { container } = renderWithConfirmContextProvider(, mockStore); + expect(container).toMatchSnapshot(); + }); + + it('renders info section for setApprovalForAll request', () => { + const state = getMockSetApprovalForAllConfirmState(); + const mockStore = configureMockStore([])(state); + const { container } = renderWithConfirmContextProvider(, mockStore); + expect(container).toMatchSnapshot(); + }); }); diff --git a/ui/pages/confirmations/components/confirm/info/info.tsx b/ui/pages/confirmations/components/confirm/info/info.tsx index 665829ecef1b..5a9c4757158e 100644 --- a/ui/pages/confirmations/components/confirm/info/info.tsx +++ b/ui/pages/confirmations/components/confirm/info/info.tsx @@ -1,12 +1,13 @@ import { TransactionType } from '@metamask/transaction-controller'; import React, { useMemo } from 'react'; -import { SignatureRequestType } from '../../../types/confirm'; import { useConfirmContext } from '../../../context/confirm'; +import { SignatureRequestType } from '../../../types/confirm'; +import ApproveInfo from './approve/approve'; import BaseTransactionInfo from './base-transaction-info/base-transaction-info'; import PersonalSignInfo from './personal-sign/personal-sign'; +import SetApprovalForAllInfo from './set-approval-for-all-info/set-approval-for-all-info'; import TypedSignV1Info from './typed-sign-v1/typed-sign-v1'; import TypedSignInfo from './typed-sign/typed-sign'; -import ApproveInfo from './approve/approve'; const Info = () => { const { currentConfirmation } = useConfirmContext(); @@ -26,6 +27,8 @@ const Info = () => { [TransactionType.deployContract]: () => BaseTransactionInfo, [TransactionType.tokenMethodApprove]: () => ApproveInfo, [TransactionType.tokenMethodIncreaseAllowance]: () => ApproveInfo, + [TransactionType.tokenMethodSetApprovalForAll]: () => + SetApprovalForAllInfo, }), [currentConfirmation], ); diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/__snapshots__/set-approval-for-all-info.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/__snapshots__/set-approval-for-all-info.test.tsx.snap new file mode 100644 index 000000000000..f46bf4028bae --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/__snapshots__/set-approval-for-all-info.test.tsx.snap @@ -0,0 +1,316 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` does not render component when no transaction is in state 1`] = `
`; + +exports[` renders component for approve request 1`] = ` +
+
+
+
+

+ Estimated changes +

+
+
+ +
+
+
+
+

+ You're giving permission for someone else to withdraw NFTs from your account. +

+
+
+
+
+

+ Withdrawing +

+
+
+
+
+

+ All +

+
+
+
+ +

+ 0x07614...3ad68 +

+
+
+
+
+
+
+
+
+
+
+

+ Data +

+
+
+ + + + + + + + + +
+
+
+
+
+

+ Request from +

+
+
+ +
+
+
+
+

+ metamask.github.io +

+
+
+
+
+
+
+

+ Network fee +

+
+
+ +
+
+
+
+

+ 0.0001 ETH +

+

+ $0.04 +

+ +
+
+
+
+

+ Speed +

+
+
+
+

+ 🦊 Market +

+

+ + ~ + 0 sec + +

+
+
+
+
+
+`; diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.test.tsx b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.test.tsx new file mode 100644 index 000000000000..3460b1d8e76e --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.test.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { + getMockConfirmState, + getMockSetApprovalForAllConfirmState, +} from '../../../../../../../test/data/confirmations/helper'; +import mockState from '../../../../../../../test/data/mock-state.json'; +import { renderWithConfirmContextProvider } from '../../../../../../../test/lib/confirmations/render-helpers'; +import SetApprovalForAllInfo from './set-approval-for-all-info'; + +jest.mock('../../../../../../store/actions', () => ({ + ...jest.requireActual('../../../../../../store/actions'), + getGasFeeTimeEstimate: jest.fn().mockResolvedValue({ + lowerTimeBound: 0, + upperTimeBound: 60000, + }), +})); + +jest.mock( + '../../../../../../components/app/alert-system/contexts/alertMetricsContext', + () => ({ + useAlertMetrics: jest.fn(() => ({ + trackAlertMetrics: jest.fn(), + })), + }), +); + +describe('', () => { + const middleware = [thunk]; + + it('renders component for approve request', async () => { + const state = getMockSetApprovalForAllConfirmState(); + + const mockStore = configureMockStore(middleware)(state); + + const { container } = renderWithConfirmContextProvider( + , + mockStore, + ); + + expect(container).toMatchSnapshot(); + }); + + it('does not render component when no transaction is in state', async () => { + const state = getMockConfirmState({ + metamask: { + ...mockState.metamask, + pendingApprovals: {}, + transactions: [], + }, + }); + + const mockStore = configureMockStore(middleware)(state); + + const { container } = renderWithConfirmContextProvider( + , + mockStore, + ); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx new file mode 100644 index 000000000000..9ed773e5a350 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx @@ -0,0 +1,33 @@ +import { TransactionMeta } from '@metamask/transaction-controller'; +import React from 'react'; +import { useSelector } from 'react-redux'; +import { useConfirmContext } from '../../../../context/confirm'; +import { selectConfirmationAdvancedDetailsOpen } from '../../../../selectors/preferences'; +import { ApproveDetails } from '../approve/approve-details/approve-details'; +import { AdvancedDetails } from '../shared/advanced-details/advanced-details'; +import { GasFeesSection } from '../shared/gas-fees-section/gas-fees-section'; +import { SetApprovalForAllStaticSimulation } from './set-approval-for-all-static-simulation/set-approval-for-all-static-simulation'; + +const SetApprovalForAllInfo = () => { + const { currentConfirmation: transactionMeta } = + useConfirmContext(); + + const showAdvancedDetails = useSelector( + selectConfirmationAdvancedDetailsOpen, + ); + + if (!transactionMeta?.txParams) { + return null; + } + + return ( + <> + + + + {showAdvancedDetails && } + + ); +}; + +export default SetApprovalForAllInfo; diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/__snapshots__/set-approval-for-all-static-simulation.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/__snapshots__/set-approval-for-all-static-simulation.test.tsx.snap new file mode 100644 index 000000000000..9f127968c09e --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/__snapshots__/set-approval-for-all-static-simulation.test.tsx.snap @@ -0,0 +1,100 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders component for approve request 1`] = ` +
+
+
+
+

+ Estimated changes +

+
+
+ +
+
+
+
+

+ You're giving permission for someone else to withdraw NFTs from your account. +

+
+
+
+
+

+ Withdrawing +

+
+
+
+
+

+ All +

+
+
+
+ +

+ 0x07614...3ad68 +

+
+
+
+
+
+
+
+`; diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.test.tsx b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.test.tsx new file mode 100644 index 000000000000..a964d008ada0 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.test.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { getMockSetApprovalForAllConfirmState } from '../../../../../../../../test/data/confirmations/helper'; +import { renderWithConfirmContextProvider } from '../../../../../../../../test/lib/confirmations/render-helpers'; +import { SetApprovalForAllStaticSimulation } from './set-approval-for-all-static-simulation'; + +describe('', () => { + const middleware = [thunk]; + + it('renders component for approve request', async () => { + const state = getMockSetApprovalForAllConfirmState(); + + const mockStore = configureMockStore(middleware)(state); + + const { container } = renderWithConfirmContextProvider( + , + mockStore, + ); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.tsx b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.tsx new file mode 100644 index 000000000000..89686f4faa7d --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.tsx @@ -0,0 +1,61 @@ +import { NameType } from '@metamask/name-controller'; +import { TransactionMeta } from '@metamask/transaction-controller'; +import React from 'react'; +import Name from '../../../../../../../components/app/name'; +import { Box, Text } from '../../../../../../../components/component-library'; +import { + AlignItems, + BackgroundColor, + BlockSize, + BorderRadius, + Display, + TextAlign, +} from '../../../../../../../helpers/constants/design-system'; +import { useI18nContext } from '../../../../../../../hooks/useI18nContext'; +import { useConfirmContext } from '../../../../../context/confirm'; +import StaticSimulation from '../../shared/static-simulation/static-simulation'; + +export const SetApprovalForAllStaticSimulation = () => { + const t = useI18nContext(); + + const { currentConfirmation: transactionMeta } = useConfirmContext() as { + currentConfirmation: TransactionMeta; + }; + + const SetApprovalForAllRow = ( + + + + {t('all')} + + + + + ); + + const simulationElements = SetApprovalForAllRow; + + return ( + + ); +}; diff --git a/ui/pages/confirmations/components/confirm/title/title.test.tsx b/ui/pages/confirmations/components/confirm/title/title.test.tsx index d886eccc7ac6..185338c2f624 100644 --- a/ui/pages/confirmations/components/confirm/title/title.test.tsx +++ b/ui/pages/confirmations/components/confirm/title/title.test.tsx @@ -2,22 +2,30 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import { + getMockApproveConfirmState, getMockContractInteractionConfirmState, getMockPersonalSignConfirmState, getMockPersonalSignConfirmStateForRequest, + getMockSetApprovalForAllConfirmState, getMockTypedSignConfirmState, getMockTypedSignConfirmStateForRequest, } from '../../../../../../test/data/confirmations/helper'; -import { renderWithConfirmContextProvider } from '../../../../../../test/lib/confirmations/render-helpers'; -import { permitSignatureMsg } from '../../../../../../test/data/confirmations/typed_sign'; import { unapprovedPersonalSignMsg } from '../../../../../../test/data/confirmations/personal_sign'; -import { Severity } from '../../../../../helpers/constants/design-system'; +import { permitSignatureMsg } from '../../../../../../test/data/confirmations/typed_sign'; +import { renderWithConfirmContextProvider } from '../../../../../../test/lib/confirmations/render-helpers'; +import { tEn } from '../../../../../../test/lib/i18n-helpers'; import { Alert, ConfirmAlertsState, } from '../../../../../ducks/confirm-alerts/confirm-alerts'; +import { Severity } from '../../../../../helpers/constants/design-system'; +import { useIsNFT } from '../info/approve/hooks/use-is-nft'; import ConfirmTitle from './title'; +jest.mock('../info/approve/hooks/use-is-nft', () => ({ + useIsNFT: jest.fn(() => ({ isNFT: true })), +})); + describe('ConfirmTitle', () => { it('should render the title and description for a personal signature', () => { const mockStore = configureMockStore([])(getMockPersonalSignConfirmState); @@ -73,7 +81,63 @@ describe('ConfirmTitle', () => { mockStore, ); - expect(getByText('Transaction request')).toBeInTheDocument(); + expect( + getByText(tEn('confirmTitleTransaction') as string), + ).toBeInTheDocument(); + }); + + it('should render the title and description for a approval transaction for NFTs', () => { + const mockStore = configureMockStore([])(getMockApproveConfirmState()); + const { getByText } = renderWithConfirmContextProvider( + , + mockStore, + ); + + expect( + getByText(tEn('confirmTitleApproveTransaction') as string), + ).toBeInTheDocument(); + expect( + getByText(tEn('confirmTitleDescApproveTransaction') as string), + ).toBeInTheDocument(); + }); + + it('should render the title and description for a approval transaction for erc20 tokens', () => { + const mockedUseIsNFT = jest.mocked(useIsNFT); + + mockedUseIsNFT.mockImplementation(() => ({ + isNFT: false, + pending: false, + })); + + const mockStore = configureMockStore([])(getMockApproveConfirmState()); + const { getByText } = renderWithConfirmContextProvider( + , + mockStore, + ); + + expect( + getByText(tEn('confirmTitlePermitTokens') as string), + ).toBeInTheDocument(); + expect( + getByText(tEn('confirmTitleDescERC20ApproveTransaction') as string), + ).toBeInTheDocument(); + }); + + it('should render the title and description for a setApprovalForAll transaction', () => { + const mockStore = configureMockStore([])( + getMockSetApprovalForAllConfirmState(), + ); + const { getByText } = renderWithConfirmContextProvider( + , + mockStore, + ); + + expect( + getByText(tEn('setApprovalForAllRedesignedTitle') as string), + ).toBeInTheDocument(); + expect( + getByText(tEn('confirmTitleDescApproveTransaction') as string), + ).toBeInTheDocument(); }); describe('Alert banner', () => { diff --git a/ui/pages/confirmations/components/confirm/title/title.tsx b/ui/pages/confirmations/components/confirm/title/title.tsx index f61fcf7d7775..ea4a3c371c7b 100644 --- a/ui/pages/confirmations/components/confirm/title/title.tsx +++ b/ui/pages/confirmations/components/confirm/title/title.tsx @@ -86,6 +86,8 @@ const getTitle = ( return t('confirmTitlePermitTokens'); case TransactionType.tokenMethodIncreaseAllowance: return t('confirmTitlePermitTokens'); + case TransactionType.tokenMethodSetApprovalForAll: + return t('setApprovalForAllRedesignedTitle'); default: return ''; } @@ -117,6 +119,8 @@ const getDescription = ( return t('confirmTitleDescERC20ApproveTransaction'); case TransactionType.tokenMethodIncreaseAllowance: return t('confirmTitleDescPermitSignature'); + case TransactionType.tokenMethodSetApprovalForAll: + return t('confirmTitleDescApproveTransaction'); default: return ''; } diff --git a/ui/pages/confirmations/utils/confirm.ts b/ui/pages/confirmations/utils/confirm.ts index a52a1a766f50..1fa7ff36085e 100644 --- a/ui/pages/confirmations/utils/confirm.ts +++ b/ui/pages/confirmations/utils/confirm.ts @@ -25,6 +25,7 @@ export const REDESIGN_DEV_TRANSACTION_TYPES = [ ...REDESIGN_USER_TRANSACTION_TYPES, TransactionType.tokenMethodApprove, TransactionType.tokenMethodIncreaseAllowance, + TransactionType.tokenMethodSetApprovalForAll, ]; const SIGNATURE_APPROVAL_TYPES = [