const { strict: assert } = require('assert'); const { withFixtures, regularDelayMs, openDapp, DAPP_URL, convertToHexValue, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); const signatureRequestType = { signTypedData: 'Sign Typed Data', signTypedDataV3: 'Sign Typed Data V3', signTypedDataV4: 'Sign Typed Data V4', }; const testData = [ { type: signatureRequestType.signTypedData, buttonId: '#signTypedData', verifyId: '#signTypedDataVerify', verifyResultId: '#signTypedDataVerifyResult', expectedMessage: 'Hi, Alice!', verifyAndAssertMessage: { titleClass: '.request-signature__content__title', originClass: '.request-signature__origin', messageClass: '.request-signature__row-value', }, }, { type: signatureRequestType.signTypedDataV3, buttonId: '#signTypedDataV3', verifyId: '#signTypedDataV3Verify', verifyResultId: '#signTypedDataV3VerifyResult', expectedMessage: 'Hello, Bob!', verifyAndAssertMessage: { titleClass: '.signature-request__content__title', originClass: '.signature-request__origin', messageClass: '.signature-request-data__node__value', }, }, { type: signatureRequestType.signTypedDataV4, buttonId: '#signTypedDataV4', verifyId: '#signTypedDataV4Verify', verifyResultId: '#signTypedDataV4VerifyResult', expectedMessage: 'Hello, Bob!', verifyAndAssertMessage: { titleClass: '.signature-request__content__title', originClass: '.signature-request__origin', messageClass: '.signature-request-data__node__value', }, }, ]; const ganacheOptions = { accounts: [ { secretKey: '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', balance: convertToHexValue(25000000000000000000), }, ], }; describe('Sign Typed Data Signature Request', function () { testData.forEach((data) => { it(`can initiate and confirm a Signature Request of ${data.type}`, async function () { await withFixtures( { dapp: true, fixtures: new FixtureBuilder() .withPermissionControllerConnectedToTestDapp() .build(), ganacheOptions, title: this.test.title, }, async ({ driver, ganacheServer }) => { const addresses = await ganacheServer.getAccounts(); const publicAddress = addresses[0]; await driver.navigate(); await driver.fill('#password', 'correct horse battery staple'); await driver.press('#password', driver.Key.ENTER); await openDapp(driver); // creates a sign typed data signature request await driver.clickElement(data.buttonId); await driver.waitUntilXWindowHandles(3); let windowHandles = await driver.getAllWindowHandles(); await driver.switchToWindowWithTitle( 'MetaMask Notification', windowHandles, ); await verifyAndAssertSignTypedData( driver, data.type, data.verifyAndAssertMessage.titleClass, data.verifyAndAssertMessage.originClass, data.verifyAndAssertMessage.messageClass, data.expectedMessage, ); // Approve signing typed data await approveSignatureRequest( driver, data.type, '[data-testid="signature-request-scroll-button"]', ); await driver.waitUntilXWindowHandles(2); windowHandles = await driver.getAllWindowHandles(); // switch to the Dapp and verify the signed address await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); await driver.clickElement(data.verifyId); const recoveredAddress = await driver.findElement( data.verifyResultId, ); assert.equal(await recoveredAddress.getText(), publicAddress); }, ); }); }); testData.forEach((data) => { it(`can queue multiple Signature Requests of ${data.type} and confirm`, async function () { await withFixtures( { dapp: true, fixtures: new FixtureBuilder() .withPermissionControllerConnectedToTestDapp() .build(), ganacheOptions, title: this.test.title, }, async ({ driver, ganacheServer }) => { const addresses = await ganacheServer.getAccounts(); const publicAddress = addresses[0]; await driver.navigate(); await driver.fill('#password', 'correct horse battery staple'); await driver.press('#password', driver.Key.ENTER); await openDapp(driver); // creates multiple sign typed data signature requests await driver.clickElement(data.buttonId); await driver.waitUntilXWindowHandles(3); const windowHandles = await driver.getAllWindowHandles(); // switches to Dapp await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); // creates second sign typed data signature request await driver.clickElement(data.buttonId); await driver.switchToWindowWithTitle( 'MetaMask Notification', windowHandles, ); await driver.waitForSelector({ text: 'Reject 2 requests', tag: 'a', }); await verifyAndAssertSignTypedData( driver, data.type, data.verifyAndAssertMessage.titleClass, data.verifyAndAssertMessage.originClass, data.verifyAndAssertMessage.messageClass, data.expectedMessage, ); // approve first signature request await approveSignatureRequest( driver, data.type, '[data-testid="signature-request-scroll-button"]', ); await driver.waitUntilXWindowHandles(3); // approve second signature request await approveSignatureRequest( driver, data.type, '[data-testid="signature-request-scroll-button"]', ); await driver.waitUntilXWindowHandles(2); // switch to the Dapp and verify the signed address for each request await driver.switchToWindowWithTitle('E2E Test Dapp'); await driver.clickElement(data.verifyId); const recoveredAddress = await driver.findElement( data.verifyResultId, ); assert.equal(await recoveredAddress.getText(), publicAddress); }, ); }); }); }); async function verifyAndAssertSignTypedData( driver, type, titleClass, originClass, messageClass, expectedMessage, ) { const title = await driver.findElement(titleClass); const origin = await driver.findElement(originClass); assert.equal(await title.getText(), 'Signature request'); assert.equal(await origin.getText(), DAPP_URL); const messages = await driver.findElements(messageClass); if (type !== signatureRequestType.signTypedData) { const verifyContractDetailsButton = await driver.findElement( '.signature-request-content__verify-contract-details', ); verifyContractDetailsButton.click(); await driver.findElement({ text: 'Third-party details', tag: 'h5' }); await driver.findElement('[data-testid="recipient"]'); await driver.clickElement({ text: 'Got it', tag: 'button' }); } const messageNumber = type === signatureRequestType.signTypedDataV3 ? 4 : 0; assert.equal(await messages[messageNumber].getText(), expectedMessage); } async function approveSignatureRequest(driver, type, buttonElementId) { if (type !== signatureRequestType.signTypedData) { await driver.clickElement(buttonElementId); } await driver.delay(regularDelayMs); await driver.clickElement({ text: 'Sign', tag: 'button' }); }