diff --git a/package.json b/package.json
index 1672e6845873..921472a1c27e 100644
--- a/package.json
+++ b/package.json
@@ -466,7 +466,7 @@
"@metamask/phishing-warning": "^4.1.0",
"@metamask/preferences-controller": "^13.0.2",
"@metamask/test-bundler": "^1.0.0",
- "@metamask/test-dapp": "8.7.0",
+ "@metamask/test-dapp": "8.13.0",
"@octokit/core": "^3.6.0",
"@open-rpc/meta-schema": "^1.14.6",
"@open-rpc/mock-server": "^1.7.5",
diff --git a/privacy-snapshot.json b/privacy-snapshot.json
index 589504ea2cc7..6e041ea3d71b 100644
--- a/privacy-snapshot.json
+++ b/privacy-snapshot.json
@@ -32,6 +32,7 @@
"localhost:8000",
"localhost:8545",
"mainnet.infura.io",
+ "metamask-sdk.api.cx.metamask.io",
"metamask.eth",
"metamask.github.io",
"metametrics.metamask.test",
diff --git a/test/e2e/tests/confirmations/signatures/nft-permit.spec.ts b/test/e2e/tests/confirmations/signatures/nft-permit.spec.ts
new file mode 100644
index 000000000000..383a3bd6b924
--- /dev/null
+++ b/test/e2e/tests/confirmations/signatures/nft-permit.spec.ts
@@ -0,0 +1,187 @@
+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';
+import { Ganache } from '../../../seeder/ganache';
+import { Driver } from '../../../webdriver/driver';
+import {
+ mockSignatureApproved,
+ mockSignatureRejected,
+ scrollAndConfirmAndAssertConfirm,
+ withRedesignConfirmationFixtures,
+} from '../helpers';
+import { TestSuiteArguments } from '../transactions/shared';
+import {
+ assertAccountDetailsMetrics,
+ assertPastedAddress,
+ assertSignatureConfirmedMetrics,
+ assertSignatureRejectedMetrics,
+ clickHeaderInfoBtn,
+ copyAddressAndPasteWalletAddress,
+ openDappAndTriggerDeploy,
+ SignatureType,
+ triggerSignature,
+} from './signature-helpers';
+
+describe('Confirmation Signature - NFT 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,
+ mockedEndpoint: mockedEndpoints,
+ }: TestSuiteArguments) => {
+ const addresses = await (ganacheServer as Ganache).getAccounts();
+ const publicAddress = addresses?.[0] as string;
+
+ await openDappAndTriggerDeploy(driver);
+ await driver.delay(1000);
+ await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
+ await driver.clickElement('[data-testid="confirm-footer-button"]');
+
+ await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
+ await driver.delay(1000);
+ await triggerSignature(driver, SignatureType.NFTPermit);
+ await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
+
+ await clickHeaderInfoBtn(driver);
+ await copyAddressAndPasteWalletAddress(driver);
+ await assertPastedAddress(driver);
+ await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
+
+ await assertInfoValues(driver);
+ await scrollAndConfirmAndAssertConfirm(driver);
+ await driver.delay(1000);
+
+ await assertAccountDetailsMetrics(
+ driver,
+ mockedEndpoints as MockedEndpoint[],
+ 'eth_signTypedData_v4',
+ );
+
+ await assertSignatureConfirmedMetrics({
+ driver,
+ mockedEndpoints: mockedEndpoints as MockedEndpoint[],
+ signatureType: 'eth_signTypedData_v4',
+ primaryType: 'Permit',
+ uiCustomizations: ['redesigned_confirmation', 'permit'],
+ });
+
+ await assertVerifiedResults(driver, publicAddress);
+ },
+ mockSignatureApproved,
+ );
+ });
+
+ it('initiates and rejects and emits the correct events', async function () {
+ await withRedesignConfirmationFixtures(
+ this.test?.fullTitle(),
+ TransactionEnvelopeType.legacy,
+ async ({
+ driver,
+ mockedEndpoint: mockedEndpoints,
+ }: TestSuiteArguments) => {
+ await openDappAndTriggerDeploy(driver);
+ await driver.delay(1000);
+ await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
+ await driver.clickElement('[data-testid="confirm-footer-button"]');
+
+ await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
+ await driver.delay(1000);
+ await triggerSignature(driver, SignatureType.NFTPermit);
+
+ await driver.clickElementAndWaitForWindowToClose(
+ '[data-testid="confirm-footer-cancel-button"]',
+ );
+
+ await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
+
+ await driver.waitForSelector({
+ tag: 'span',
+ text: 'Error: User rejected the request.',
+ });
+
+ await assertSignatureRejectedMetrics({
+ driver,
+ mockedEndpoints: mockedEndpoints as MockedEndpoint[],
+ signatureType: 'eth_signTypedData_v4',
+ primaryType: 'Permit',
+ uiCustomizations: ['redesigned_confirmation', 'permit'],
+ location: 'confirmation',
+ });
+ },
+ mockSignatureRejected,
+ );
+ });
+});
+
+async function assertInfoValues(driver: Driver) {
+ await driver.clickElement('[data-testid="sectionCollapseButton"]');
+ const origin = driver.findElement({ text: DAPP_HOST_ADDRESS });
+ const contractPetName = driver.findElement({
+ css: '.name__value',
+ text: '0x581c3...45947',
+ });
+
+ const title = driver.findElement({ text: 'Withdrawal request' });
+ const description = driver.findElement({
+ text: 'This site wants permission to withdraw your NFTs',
+ });
+ const primaryType = driver.findElement({ text: 'Permit' });
+ const spender = driver.findElement({
+ css: '.name__value',
+ text: '0x581c3...45947',
+ });
+ const tokenId = driver.findElement({ text: '3606393' });
+ const nonce = driver.findElement({ text: '0' });
+ const deadline = driver.findElement({ text: '23 December 2024, 23:03' });
+
+ assert.ok(await origin, 'origin');
+ assert.ok(await contractPetName, 'contractPetName');
+ assert.ok(await title, 'title');
+ assert.ok(await description, 'description');
+ assert.ok(await primaryType, 'primaryType');
+ assert.ok(await spender, 'spender');
+ assert.ok(await tokenId, 'tokenId');
+ assert.ok(await nonce, 'nonce');
+ assert.ok(await deadline, 'deadline');
+}
+
+async function assertVerifiedResults(driver: Driver, publicAddress: string) {
+ await driver.waitUntilXWindowHandles(2);
+ await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
+ await driver.clickElement('#sign721PermitVerify');
+
+ await driver.waitForSelector({
+ css: '#sign721PermitVerifyResult',
+ text: publicAddress,
+ });
+
+ await driver.waitForSelector({
+ css: '#sign721PermitResult',
+ text: '0x572bc6300f6aa669e85e0a7792bc0b0803fb70c3c492226b30007ff7030b03600e390ef295a5a525d19f444943ae82697f0e5b5b0d77cc382cb2ea9486ec27801c',
+ });
+
+ await driver.waitForSelector({
+ css: '#sign721PermitResultR',
+ text: 'r: 0x572bc6300f6aa669e85e0a7792bc0b0803fb70c3c492226b30007ff7030b0360',
+ });
+
+ await driver.waitForSelector({
+ css: '#sign721PermitResultS',
+ text: 's: 0x0e390ef295a5a525d19f444943ae82697f0e5b5b0d77cc382cb2ea9486ec2780',
+ });
+
+ await driver.waitForSelector({
+ css: '#sign721PermitResultV',
+ text: 'v: 28',
+ });
+
+ await driver.waitForSelector({
+ css: '#sign721PermitVerifyResult',
+ text: publicAddress,
+ });
+}
diff --git a/test/e2e/tests/confirmations/signatures/signature-helpers.ts b/test/e2e/tests/confirmations/signatures/signature-helpers.ts
index 9b87e5b4e9cc..5242be3f3c20 100644
--- a/test/e2e/tests/confirmations/signatures/signature-helpers.ts
+++ b/test/e2e/tests/confirmations/signatures/signature-helpers.ts
@@ -14,6 +14,7 @@ export const WALLET_ETH_BALANCE = '25';
export enum SignatureType {
PersonalSign = '#personalSign',
Permit = '#signPermit',
+ NFTPermit = '#sign721Permit',
SignTypedDataV3 = '#signTypedDataV3',
SignTypedDataV4 = '#signTypedDataV4',
SignTypedData = '#signTypedData',
@@ -240,12 +241,23 @@ export async function assertPastedAddress(driver: Driver) {
assert.equal(await formFieldEl.getAttribute('value'), WALLET_ADDRESS);
}
+export async function triggerSignature(driver: Driver, type: string) {
+ await driver.clickElement(type);
+ await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
+}
+
export async function openDappAndTriggerSignature(
driver: Driver,
type: string,
) {
await unlockWallet(driver);
await openDapp(driver);
- await driver.clickElement(type);
+ await triggerSignature(driver, type);
+}
+
+export async function openDappAndTriggerDeploy(driver: Driver) {
+ await unlockWallet(driver);
+ await openDapp(driver);
+ await driver.clickElement('#deployNFTsButton');
await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
}
diff --git a/test/e2e/tests/tokens/add-multiple-tokens.spec.js b/test/e2e/tests/tokens/add-multiple-tokens.spec.js
index 490460e770cb..8be2a430b622 100644
--- a/test/e2e/tests/tokens/add-multiple-tokens.spec.js
+++ b/test/e2e/tests/tokens/add-multiple-tokens.spec.js
@@ -28,6 +28,11 @@ describe('Multiple ERC20 Watch Asset', function () {
await openDapp(driver, undefined, DAPP_URL);
// Create Token 1
+ const createToken = await driver.findElement({
+ text: 'Create Token',
+ tag: 'button',
+ });
+ await driver.scrollToElement(createToken);
await driver.clickElement({ text: 'Create Token', tag: 'button' });
await switchToNotificationWindow(driver);
await driver.findClickableElement({ text: 'Confirm', tag: 'button' });
@@ -37,7 +42,7 @@ describe('Multiple ERC20 Watch Asset', function () {
await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
await driver.wait(async () => {
const tokenAddressesElement = await driver.findElement(
- '#tokenAddresses',
+ '#erc20TokenAddresses',
);
const tokenAddresses = await tokenAddressesElement.getText();
return tokenAddresses !== '';
@@ -53,7 +58,7 @@ describe('Multiple ERC20 Watch Asset', function () {
await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
await driver.wait(async () => {
const tokenAddressesElement = await driver.findElement(
- '#tokenAddresses',
+ '#erc20TokenAddresses',
);
const tokenAddresses = await tokenAddressesElement.getText();
return tokenAddresses.split(',').length === 2;
@@ -69,7 +74,7 @@ describe('Multiple ERC20 Watch Asset', function () {
await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
await driver.wait(async () => {
const tokenAddressesElement = await driver.findElement(
- '#tokenAddresses',
+ '#erc20TokenAddresses',
);
const tokenAddresses = await tokenAddressesElement.getText();
return tokenAddresses.split(',').length === 3;
diff --git a/ui/pages/confirmations/components/confirm/info/base-transaction-info/base-transaction-info.tsx b/ui/pages/confirmations/components/confirm/info/base-transaction-info/base-transaction-info.tsx
index 08329536b524..23629ee5096c 100644
--- a/ui/pages/confirmations/components/confirm/info/base-transaction-info/base-transaction-info.tsx
+++ b/ui/pages/confirmations/components/confirm/info/base-transaction-info/base-transaction-info.tsx
@@ -22,6 +22,7 @@ const BaseTransactionInfo = () => {
diff --git a/ui/pages/confirmations/components/confirm/info/native-transfer/native-transfer.tsx b/ui/pages/confirmations/components/confirm/info/native-transfer/native-transfer.tsx
index a2dd3ceaaa05..c098936989dd 100644
--- a/ui/pages/confirmations/components/confirm/info/native-transfer/native-transfer.tsx
+++ b/ui/pages/confirmations/components/confirm/info/native-transfer/native-transfer.tsx
@@ -24,6 +24,7 @@ const NativeTransferInfo = () => {
)}
diff --git a/ui/pages/confirmations/components/confirm/info/nft-token-transfer/nft-token-transfer.tsx b/ui/pages/confirmations/components/confirm/info/nft-token-transfer/nft-token-transfer.tsx
index b5d579994ef9..113920a6aec2 100644
--- a/ui/pages/confirmations/components/confirm/info/nft-token-transfer/nft-token-transfer.tsx
+++ b/ui/pages/confirmations/components/confirm/info/nft-token-transfer/nft-token-transfer.tsx
@@ -24,6 +24,7 @@ const NFTTokenTransferInfo = () => {
)}
diff --git a/ui/pages/confirmations/components/confirm/info/token-transfer/token-transfer.tsx b/ui/pages/confirmations/components/confirm/info/token-transfer/token-transfer.tsx
index df1136ec5213..50e9d85936f0 100644
--- a/ui/pages/confirmations/components/confirm/info/token-transfer/token-transfer.tsx
+++ b/ui/pages/confirmations/components/confirm/info/token-transfer/token-transfer.tsx
@@ -24,6 +24,7 @@ const TokenTransferInfo = () => {
)}
diff --git a/yarn.lock b/yarn.lock
index 9ac1b7409679..4c3305e98b13 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6386,10 +6386,10 @@ __metadata:
languageName: node
linkType: hard
-"@metamask/test-dapp@npm:8.7.0":
- version: 8.7.0
- resolution: "@metamask/test-dapp@npm:8.7.0"
- checksum: 10/c2559179d3372e5fc8d67a60c1e4056fad9809486eaff6a2aa9c351a2a613eeecc15885a5fd9b71b8f4139058fe168abeac06bd6bdb6d4a47fe0b9b4146923ab
+"@metamask/test-dapp@npm:8.13.0":
+ version: 8.13.0
+ resolution: "@metamask/test-dapp@npm:8.13.0"
+ checksum: 10/b588e562ce81d94e22e8c19b6b160b6dc1c5f68314edaeeb3c886a0676d4bd21205c741d039a1a8ad2dfc1e87109239d18da17c322fbaa99f527b543b0032786
languageName: node
linkType: hard
@@ -26470,7 +26470,7 @@ __metadata:
"@metamask/snaps-sdk": "npm:^6.10.0"
"@metamask/snaps-utils": "npm:^8.5.1"
"@metamask/test-bundler": "npm:^1.0.0"
- "@metamask/test-dapp": "npm:8.7.0"
+ "@metamask/test-dapp": "npm:8.13.0"
"@metamask/transaction-controller": "npm:^38.1.0"
"@metamask/user-operation-controller": "npm:^13.0.0"
"@metamask/utils": "npm:^9.3.0"