A Metamask fork with Infura removed and default networks editable
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ciphermask/test/e2e/metamask-ui.spec.js

976 lines
32 KiB

const { strict: assert } = require('assert');
const path = require('path');
const enLocaleMessages = require('../../app/_locales/en/messages.json');
const createStaticServer = require('../../development/create-static-server');
const { tinyDelayMs, regularDelayMs, largeDelayMs } = require('./helpers');
const { buildWebDriver } = require('./webdriver');
const Ganache = require('./ganache');
Fix 'yarn setup' on M1 Macs (#11887) There are a few issues encountered when running `yarn setup` on new Apple Silicon (aka M1, aka arm64) Macs: * The script halts when attempting to run the install step for the `chromedriver` package with the message "Only Mac 64 bits supported". This is somewhat misleading as it seems to indicate that chromedriver can only be installed on a 64-bit Mac. However, what I think is happening is that the installation script for `chromedriver` is not able to detect that an arm64 CPU *is* a 64-bit CPU. After looking through the `chromedriver` repo, it appears that 87.0.1 is the first version that adds a proper check ([1]). Note that upgrading chromedriver caused the Chrome-specific tests to fail intermittently on CI. I was not able to 100% work out the reason for this, but ensuring that X (which provides a way for Chrome to run in a GUI setting from the command line) is available seems to fix these issues. * The script also halts when attempting to run the install step for the `electron` package. This happens because for the version of `electron` we are using (9.4.2), there is no available binary for arm64. It appears that Electron 11.x was the first version to support arm64 Macs ([2]). This is a bit trickier to resolve because we don't explicitly rely on `electron` — that's brought in by `react-devtools`. The first version of `react-devtools` that relies on `electron` 11.x is 4.11.0 ([3]). [1]: https://github.com/giggio/node-chromedriver/commit/469dd0a6ee23540bfa832b5f09b4cbde3e152010 [2]: https://www.electronjs.org/blog/apple-silicon [3]: https://github.com/facebook/react/blob/main/packages/react-devtools/CHANGELOG.md#4110-april-9-2021
3 years ago
const { ensureXServerIsRunning } = require('./x-server');
const ganacheServer = new Ganache();
const dappPort = 8080;
describe('MetaMask', function () {
let driver;
let dappServer;
let tokenAddress;
const testSeedPhrase =
'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent';
this.bail(true);
let failed = false;
before(async function () {
await ganacheServer.start();
const dappDirectory = path.resolve(
__dirname,
'..',
'..',
'node_modules',
'@metamask',
'test-dapp',
'dist',
);
dappServer = createStaticServer(dappDirectory);
dappServer.listen(dappPort);
await new Promise((resolve, reject) => {
dappServer.on('listening', resolve);
dappServer.on('error', reject);
});
Fix 'yarn setup' on M1 Macs (#11887) There are a few issues encountered when running `yarn setup` on new Apple Silicon (aka M1, aka arm64) Macs: * The script halts when attempting to run the install step for the `chromedriver` package with the message "Only Mac 64 bits supported". This is somewhat misleading as it seems to indicate that chromedriver can only be installed on a 64-bit Mac. However, what I think is happening is that the installation script for `chromedriver` is not able to detect that an arm64 CPU *is* a 64-bit CPU. After looking through the `chromedriver` repo, it appears that 87.0.1 is the first version that adds a proper check ([1]). Note that upgrading chromedriver caused the Chrome-specific tests to fail intermittently on CI. I was not able to 100% work out the reason for this, but ensuring that X (which provides a way for Chrome to run in a GUI setting from the command line) is available seems to fix these issues. * The script also halts when attempting to run the install step for the `electron` package. This happens because for the version of `electron` we are using (9.4.2), there is no available binary for arm64. It appears that Electron 11.x was the first version to support arm64 Macs ([2]). This is a bit trickier to resolve because we don't explicitly rely on `electron` — that's brought in by `react-devtools`. The first version of `react-devtools` that relies on `electron` 11.x is 4.11.0 ([3]). [1]: https://github.com/giggio/node-chromedriver/commit/469dd0a6ee23540bfa832b5f09b4cbde3e152010 [2]: https://www.electronjs.org/blog/apple-silicon [3]: https://github.com/facebook/react/blob/main/packages/react-devtools/CHANGELOG.md#4110-april-9-2021
3 years ago
if (process.env.SELENIUM_BROWSER === 'chrome') {
await ensureXServerIsRunning();
}
const result = await buildWebDriver();
driver = result.driver;
await driver.navigate();
});
afterEach(async function () {
if (process.env.SELENIUM_BROWSER === 'chrome') {
const errors = await driver.checkBrowserForConsoleErrors(driver);
if (errors.length) {
const errorReports = errors.map((err) => err.message);
const errorMessage = `Errors found in browser console:\n${errorReports.join(
'\n',
)}`;
console.error(new Error(errorMessage));
}
}
if (this.currentTest.state === 'failed') {
failed = true;
await driver.verboseReportOnFailure(this.currentTest.title);
}
});
after(async function () {
if (process.env.E2E_LEAVE_RUNNING === 'true' && failed) {
return;
}
await ganacheServer.quit();
await driver.quit();
await new Promise((resolve, reject) => {
dappServer.close((error) => {
if (error) {
return reject(error);
}
return resolve();
});
});
});
describe('Going through the first time flow', function () {
it('clicks the continue button on the welcome screen', async function () {
await driver.findElement('.welcome-page__header');
await driver.clickElement({
text: enLocaleMessages.getStarted.message,
tag: 'button',
});
await driver.delay(largeDelayMs);
});
it('clicks the "Create New Wallet" option', async function () {
await driver.clickElement({ text: 'Create a Wallet', tag: 'button' });
await driver.delay(largeDelayMs);
});
it('clicks the "No thanks" option on the metametrics opt-in screen', async function () {
await driver.clickElement('.btn-default');
await driver.delay(largeDelayMs);
});
Metametrics (#6171) * Add metametrics provider and util. * Add backend api and state for participating in metametrics. * Add frontend action for participating in metametrics. * Add metametrics opt-in screen. * Add metametrics events to first time flow. * Add metametrics events for route changes * Add metametrics events for send and confirm screens * Add metametrics events to dropdowns, transactions, log in and out, settings, sig requests and main screen * Ensures each log in is measured as a new visit by metametrics. * Ensure metametrics is called with an empty string for dimensions params if specified * Adds opt in metametrics modal after unlock for existing users * Adds settings page toggle for opting in and out of MetaMetrics * Switch metametrics dimensions to page level scope * Lint, test and translation fixes for metametrics. * Update design for metametrics opt-in screen * Complete responsive styling of metametrics-opt-in modal * Use new chart image on metrics opt in screens * Incorporate the metametrics opt-in screen into the new onboarding flow * Update e2e tests to accomodate metametrics changes * Mock out metametrics network requests in integration tests * Fix tx-list integration test to support metametrics provider. * Send number of tokens and accounts data with every metametrics event. * Update metametrics event descriptor schema and add new events. * Fix import tos bug and send gas button bug due to metametrics changes. * Various small fixes on the metametrics branch. * Add origin custom variable type to metametrics.util * Fix names of onboarding complete actions (metametrics). * Fix names of Metrics Options actions (metametrics). * Clean up code related to metametrics. * Fix bad merge conflict resolution and improve promise handling in sendMetaMetrics event and confrim tx base * Don't send a second metrics event if user has gone back during first time flow. * Collect metametrics on going back from onboarding create/import. * Add missing custom variable constants for metametrics * Fix metametrics provider * Make height of opt-in modal responsive. * Adjust text content for opt-in modal. * Update metametrics event names and clean up code in opt-in-modal * Put phishing warning step next to last in onboarding flow * Link terms of service on create and import screens of first time flow * Add subtext to options on the onboarding select action screen. * Fix styling of bullet points on end of onboarding screen. * Combine phishing warning and congratulations screens. * Fix placement of users if unlocking after an incomplete onboarding import flow. * Fix capitalization in opt-in screen * Fix last onboarding screen translations * Add link to 'Learn More' on the last screen of onboarding * Code clean up: metametrics branch * Update e2e tests for phishing warning step removal * e2e tests passing on metametrics branch * Different tracking urls for metametrics on development and prod
6 years ago
it('accepts a secure password', async function () {
await driver.fill(
'.first-time-flow__form #create-password',
'correct horse battery staple',
);
await driver.fill(
'.first-time-flow__form #confirm-password',
'correct horse battery staple',
);
await driver.clickElement('.first-time-flow__checkbox');
await driver.clickElement('.first-time-flow__form button');
await driver.delay(regularDelayMs);
});
let seedPhrase;
it('renders the Secret Recovery Phrase intro screen', async function () {
await driver.clickElement('.seed-phrase-intro__left button');
await driver.delay(regularDelayMs);
});
it('reveals the Secret Recovery Phrase', async function () {
const byRevealButton =
'.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button';
await driver.findElement(byRevealButton);
await driver.clickElement(byRevealButton);
await driver.delay(regularDelayMs);
const revealedSeedPhrase = await driver.findElement(
'.reveal-seed-phrase__secret-words',
);
seedPhrase = await revealedSeedPhrase.getText();
assert.equal(seedPhrase.split(' ').length, 12);
await driver.delay(regularDelayMs);
await driver.clickElement({
text: enLocaleMessages.next.message,
tag: 'button',
});
await driver.delay(regularDelayMs);
});
async function clickWordAndWait(word) {
await driver.clickElement(
`[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`,
);
await driver.delay(tinyDelayMs);
}
it('can retype the Secret Recovery Phrase', async function () {
const words = seedPhrase.split(' ');
for (const word of words) {
await clickWordAndWait(word);
}
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.delay(regularDelayMs);
});
it('clicks through the success screen', async function () {
await driver.findElement({ text: 'Congratulations', tag: 'div' });
await driver.clickElement({
text: enLocaleMessages.endOfFlowMessage10.message,
tag: 'button',
});
await driver.delay(regularDelayMs);
});
});
Whats new popup (#10583) * Add 'What's New' notification popup * Move selectors from shared/notifications into ui/ directory * Use keys for localized message in whats new notifications objects, to ensure notifications will be translated. * Remove unused swaps intro popup locale messages * Fix keys of whats new notification locales * Remove notifications messages and descriptions from comment in shared/notifications * Move notifcationActionFunctions to shared/notifications and make it stateless * Get notification data from constants instead of state in whats-new-popup * Code cleanup * Fix build quote reference to swapsEthToken, broken during rebase * Rename notificationFilters to notificationToExclude to clarify its purpose * Documentation for getSortedNotificationsToShow * Move notification action functions from shared/ to whats-new-popup.js * Stop setting swapsWelcomeMessageHasBeenShown to state in app-state controller * Update e2e tests for whats new popup changes * Updating migration files * Addressing feedback part 1 * Addressing feedback part 2 * Remove unnecessary div in whats-new-popup * Change getNotificationsToExclude to getNotificationsToInclude for use in the getSortedNotificationsToShow selector * Delete intro-popup directory and test files * Lint fix * Add notifiction state to address-entry fixture * Use two separate functions for rendering first and subsequent notifications in the whats-new-popup * Ensure that string literals are passed to t for whats new popup text * Update import-ui fixtures to include notificaiton controller state * Remove unnecessary, accidental change confirm-approve * Remove swaps notification in favour of mobile swaps as first notifcation and TBD 3rd notification * Update whats-new-popup to use intersection observer api to detect if notification has been seen * Add notifications to send-edit and threebox e2e test fixtures * Update ui/app/selectors/selectors.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * Update ui/app/selectors/selectors.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * Clean up locale code for whats-new-popup notifications * Disconnect observers in whats-new-popup when their callback is first called * Add test case for migration 58 for when the AppStateController does not exist * Rename popover components containerRef to popoverWrapRef * Fix messages.json * Update notification messages and images * Rename popoverWrapRef -> popoverRef in whats-new-popup and popover.component * Only create one observer, and only after images have loaded, in whats-new-popup * Set width and height on whats-new-popup image, instead of setting state on img load * Update ui/app/components/app/whats-new-popup/whats-new-popup.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * Code clean up in whats new popup re: notification rendering and action functions * Code cleanup in render notification functions of whats-new-popup * Update ui/app/components/app/whats-new-popup/whats-new-popup.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * lint fix * Update and localize notification dates * Clean up date code in shred/notifications/index.js Co-authored-by: ryanml <ryanlanese@gmail.com> Co-authored-by: Mark Stacey <markjstacey@gmail.com>
4 years ago
describe("Close the what's new popup", function () {
it("should show the what's new popover", async function () {
const popoverTitle = await driver.findElement(
'.popover-header__title h2',
);
assert.equal(await popoverTitle.getText(), "What's new");
});
it("should close the what's new popup", async function () {
const popover = await driver.findElement('.popover-container');
await driver.clickElement('[data-testid="popover-close"]');
await popover.waitForElementState('hidden');
});
});
describe('Import Secret Recovery Phrase', function () {
it('logs out of the vault', async function () {
await driver.clickElement('.account-menu__icon');
await driver.delay(regularDelayMs);
const lockButton = await driver.findClickableElement(
'.account-menu__lock-button',
);
assert.equal(await lockButton.getText(), 'Lock');
await lockButton.click();
await driver.delay(regularDelayMs);
});
it('imports Secret Recovery Phrase', async function () {
const restoreSeedLink = await driver.findClickableElement(
'.unlock-page__link--import',
);
assert.equal(
await restoreSeedLink.getText(),
'import using Secret Recovery Phrase',
);
await restoreSeedLink.click();
await driver.delay(regularDelayMs);
await driver.clickElement('.import-account__checkbox-container');
await driver.fill('.import-account__secret-phrase', testSeedPhrase);
await driver.delay(regularDelayMs);
await driver.fill('#password', 'correct horse battery staple');
await driver.fill('#confirm-password', 'correct horse battery staple');
await driver.clickElement({
text: enLocaleMessages.restore.message,
tag: 'button',
});
await driver.delay(regularDelayMs);
});
it('balance renders', async function () {
await driver.waitForSelector({
css: '[data-testid="wallet-balance"] .list-item__heading',
text: '100 ETH',
});
await driver.delay(regularDelayMs);
});
});
describe('Navigate transactions', function () {
let windowHandles;
let extension;
let popup;
let dapp;
it('connects the dapp', async function () {
await driver.openNewPage('http://127.0.0.1:8080/');
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Connect', tag: 'button' });
Add support for one-click onboarding (#7017) * Add support for one-click onboarding MetaMask now allows sites to register as onboarding the user, so that the user is redirected back to the initiating site after onboarding. This is accomplished through the use of the `metamask-onboarding` library and the MetaMask forwarder. At the end of onboarding, a 'snackbar'-stype component will explain to the user they are about to be moved back to the originating dapp, and it will show the origin of that dapp. This is intended to help prevent phishing attempts, as it highlights that a redirect is taking place to an untrusted third party. If the onboarding initiator tab is closed when onboarding is finished, the user is redirected to the onboarding originator as a fallback. Closes #6161 * Add onboarding button to contract test dapp The `contract-test` dapp (run with `yarn dapp`, used in e2e tests) now uses a `Connect` button instead of connecting automatically. This button also serves as an onboarding button when a MetaMask installation is not detected. * Add new static server for test dapp The `static-server` library we were using for the `contract-test` dapp didn't allow referencing files outside the server root. This should have been possible to work around using symlinks, but there was a bug that resulted in symlinks crashing the server. Instead it has been replaced with a simple static file server that will serve paths starting with `node_modules` from the project root. This will be useful in testing the onboarding library without vendoring it. * Add `@metamask/onboarding` and `@metamask/forwarder` Both libraries used to test onboarding are now included as dev dependencies, to help with testing. A few convenience scripts were added to help with this (`yarn forwarder` and `yarn dapp-forwarder`)
5 years ago
await driver.delay(regularDelayMs);
Add support for one-click onboarding (#7017) * Add support for one-click onboarding MetaMask now allows sites to register as onboarding the user, so that the user is redirected back to the initiating site after onboarding. This is accomplished through the use of the `metamask-onboarding` library and the MetaMask forwarder. At the end of onboarding, a 'snackbar'-stype component will explain to the user they are about to be moved back to the originating dapp, and it will show the origin of that dapp. This is intended to help prevent phishing attempts, as it highlights that a redirect is taking place to an untrusted third party. If the onboarding initiator tab is closed when onboarding is finished, the user is redirected to the onboarding originator as a fallback. Closes #6161 * Add onboarding button to contract test dapp The `contract-test` dapp (run with `yarn dapp`, used in e2e tests) now uses a `Connect` button instead of connecting automatically. This button also serves as an onboarding button when a MetaMask installation is not detected. * Add new static server for test dapp The `static-server` library we were using for the `contract-test` dapp didn't allow referencing files outside the server root. This should have been possible to work around using symlinks, but there was a bug that resulted in symlinks crashing the server. Instead it has been replaced with a simple static file server that will serve paths starting with `node_modules` from the project root. This will be useful in testing the onboarding library without vendoring it. * Add `@metamask/onboarding` and `@metamask/forwarder` Both libraries used to test onboarding are now included as dev dependencies, to help with testing. A few convenience scripts were added to help with this (`yarn forwarder` and `yarn dapp-forwarder`)
5 years ago
await driver.waitUntilXWindowHandles(3);
windowHandles = await driver.getAllWindowHandles();
extension = windowHandles[0];
dapp = await driver.switchToWindowWithTitle(
'E2E Test Dapp',
windowHandles,
);
popup = windowHandles.find(
(handle) => handle !== extension && handle !== dapp,
);
Connect distinct accounts per site (#7004) * add PermissionsController remove provider approval controller integrate rpc-cap create PermissionsController move provider approval functionality to permissions controller add permissions approval ui, settings page add permissions activity and history move some functionality to metamask-inpage-provider rename siteMetadata -> domainMetadata add accountsChange notification to inpage provider move functionality to inpage provider update inpage provider Remove 'Connections' settings page (#7369) add hooks for exposing accounts in settings rename unused messages in non-English locales Add external extension id to metadata (#7396) update inpage provider, rpc-cap add eth_requestAccounts handling to background prevent notifying connections if extension is locked update inpage provider Fix lint errors add migration review fixes transaction controller review updates removed unused messages * Login Per Site UI (#7368) * LoginPerSite original UI changes to keep * First commit * Get necessary connected tab info for redirect and icon display for permissioned sites * Fix up designs and add missing features * Some lint fixes * More lint fixes * Ensures the tx controller + tx-state-manager orders transactions in the order they are received * Code cleanup for LoginPerSite-ui * Update e2e tests to use new connection flow * Fix display of connect screen and app header after login when connect request present * Update metamask-responsive-ui.spec for new item in accounts dropdown * Fix approve container by replacing approvedOrigins with domainMetaData * Adds test/e2e/permissions.spec.js * Correctly handle cancellation of a permissions request * Redirect to home after disconnecting all sites / cancelling all permissions * Fix display of site icons in menu * Fix height of permissions page container * Remove unused locale messages * Set default values for openExternalTabs and tabIdOrigins in account-menu.container * More code cleanup for LoginPerSite-ui * Use extensions api to close tab in permissions-connect * Remove unnecessary change in domIsReady() in contentscript * Remove unnecessary private function markers and class methods (for background tab info) in metamask-controller. * Adds getOriginOfCurrentTab selector * Adds IconWithFallback component and substitutes for appropriate cases * Add and utilize font mixins * Remove unused method in disconnect-all.container.js * Simplify buttonSizeLarge code in page-container-footer.component.js * Add and utilize getAccountsWithLabels selector * Remove console.log in ui/app/store/actions.js * Change last connected time format to yyyy-M-d * Fix css associated with IconWithFallback change * Ensure tracked openNonMetamaskTabsIDs are correctly set to inactive on tab changes * Code cleanup for LoginPerSite-ui * Use reusable function for modifying openNonMetamaskTabsIDs in background.js * Enables automatic switching to connected account when connected domain is open * Prevent exploit of tabIdOriginMap in background.js * Remove unneeded code from contentscript.js * Simplify current tab origin and window opener logic using remotePort listener tabs.queryTabs * Design and styling fixes for LoginPerSite-ui * Fix permissionHistory and permission logging for eth_requestAccounts and eth_accounts * Front end changes to support display of lastConnected time in connected and permissions screens * Fix lint errors * Refactor structure of permissionsHistory * Fix default values and object modifications for domain and permissionsHistory related data * Fix connecting to new accounts from modal * Replace retweet.svg with connect-white.svg * Fix signature-request.spec * Update metamask-inpage-provider version * Fix permissions e2e tests * Remove unneeded delay from test/e2e/signature-request.spec.js * Add delay before attempting to retrieve network id in dapp in ethereum-on=.spec * Use requestAccountTabIds strategy for determining tab id that opened a given window * Improve default values for permissions requests * Add some message descriptions to app/_locales/en/messages.json * Code clean up in permission controller * Stopped deep cloning object in mapObjectValues * Bump metamask-inpage-provider version * Add missing description in app/_locales/en/messages.json * Return promises from queryTabs and switchToTab of extension.js * Remove unused getAllPermissions function * Use default props in icon-with-fallback.component.js * Stop passing to permissions controller * Delete no longer used clear-approved-origins modal code * Remove duplicate imports in ui/app/components/app/index.scss * Use URL instead of regex in getOriginFromUrl() * Add runtime error checking to platform, promise based extension.tab methods * Support permission requests from external extensions * Improve font size and colour of the domain origin on the permission confirmation screen * Add support for toggling permissions * Ensure getRenderablePermissionsDomains only returns domains with exposedAccount caveat permissions * Remove unused code from LoginPerSite-ui branch * Ensure modal closes on Enter press for new-account-modal.component.js * Lint fix * fixup! Login Per Site UI (#7368) * Some code cleanup for LoginPerSite * Adds UX for connecting to dapps via the connected sites screen (#7593) * Adds UX for connecting to dapps via the connected sites screen * Use openMetaMaskTabIds from background.js to determine if current active tab is MetaMask * Delete unused permissions controller methods * Fixes two small bugs in the LoginPerSite ui (#7595) * Restore `providerRequest` message translations (#7600) This message was removed, but it was replaced with a very similar message called `likeToConnect`. The only difference is that the new message has "MetaMask" in it. Preserving these messages without "MetaMask" is probably better than deleting them, so these messages have all been restored and renamed to `likeToConnect`. * Login per site no sitemetadata fix (#7610) * Support connected sites for which we have no site metadata. * Change property containing subtitle info often populated by origin to a more accurate of purpose name * Lint fix * Improve disconnection modal messages (#7612) * Improve disconnectAccountModalDescription and disconnectAllModalDescription messages * Update disconnectAccountModalDescription app/_locales/en/messages.json Co-Authored-By: Mark Stacey <markjstacey@gmail.com> * Improve disconnectAccount modal message clarity * Adds cancel button to the account selection screen of the permissions request flow (#7613) * Fix eth_accounts permission language & selectability (#7614) * fix eth_accounts language & selectability * fix MetaMask capitalization in all messages * Close sidebar when opening connected sites (#7611) The 'Connected Sites' button in the accounts details now closes the sidebar, if it is open. This was accomplished by pulling the click handler for that button up to the wallet view component, where another button already followed a similar pattern of closing the sidebar. It seemed confusing to me that one handler was in the `AccountsDetails` container component, and one was handed down from above, so I added PropTypes to the container component. I'm not sure that the WalletView component is the best place for this logic, but I've put it there for now to be consistent with the add token button. * Reject permissions request upon tab close (#7618) Permissions requests are now rejected when the page is closed. This only applies to the full-screen view, as that is the view permission requests should be handled in. The case where the user deals with the request through a different view is handled in #7617 * Handle tab update failure (#7619) `extension.tabs.update` can sometimes fail if the user interacts with the tabs directly around the same time. The redirect flow has been updated to ensure that the permissions tab is still closed in that case. The user is on their own to find the dapp tab again in that case. * Login per site tab popup fixes (#7617) * Handle redirect in response to state update in permissions-connect * Ensure origin is available to permissions-connect subcomponents during redirect * Hide app bar whenever on redirect route * Improvements to handling of redirects in permissions-connect * Ensure permission request id change handling only happens when page is not null * Lint fix * Decouple confirm transaction screen from the selected address (#7622) * Avoid race condtion that could prevent contextual account switching (#7623) There was a race condition in the logic responsible for switching the selected account based upon the active tab. It was asynchronously querying the active tab, then assuming it had been retrieved later. The active tab info itself was already in the redux store in another spot, one that is guaranteed to be set before the UI renders. The race condition was avoided by deleting the duplicate state, and using the other active tab state. * Only redirect back to dapp if current tab is active (#7621) The "redirect back to dapp" behaviour can be disruptive when the permissions connect tab is not active. The purpose of the redirect was to maintain context between the dapp and the permissions request, but if the user has already moved to another tab, that no longer applies. * Fix JSX style lint errors * Remove unused state
5 years ago
await driver.switchToWindow(popup);
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Next', tag: 'button' });
await driver.clickElement({ text: 'Connect', tag: 'button' });
Connect distinct accounts per site (#7004) * add PermissionsController remove provider approval controller integrate rpc-cap create PermissionsController move provider approval functionality to permissions controller add permissions approval ui, settings page add permissions activity and history move some functionality to metamask-inpage-provider rename siteMetadata -> domainMetadata add accountsChange notification to inpage provider move functionality to inpage provider update inpage provider Remove 'Connections' settings page (#7369) add hooks for exposing accounts in settings rename unused messages in non-English locales Add external extension id to metadata (#7396) update inpage provider, rpc-cap add eth_requestAccounts handling to background prevent notifying connections if extension is locked update inpage provider Fix lint errors add migration review fixes transaction controller review updates removed unused messages * Login Per Site UI (#7368) * LoginPerSite original UI changes to keep * First commit * Get necessary connected tab info for redirect and icon display for permissioned sites * Fix up designs and add missing features * Some lint fixes * More lint fixes * Ensures the tx controller + tx-state-manager orders transactions in the order they are received * Code cleanup for LoginPerSite-ui * Update e2e tests to use new connection flow * Fix display of connect screen and app header after login when connect request present * Update metamask-responsive-ui.spec for new item in accounts dropdown * Fix approve container by replacing approvedOrigins with domainMetaData * Adds test/e2e/permissions.spec.js * Correctly handle cancellation of a permissions request * Redirect to home after disconnecting all sites / cancelling all permissions * Fix display of site icons in menu * Fix height of permissions page container * Remove unused locale messages * Set default values for openExternalTabs and tabIdOrigins in account-menu.container * More code cleanup for LoginPerSite-ui * Use extensions api to close tab in permissions-connect * Remove unnecessary change in domIsReady() in contentscript * Remove unnecessary private function markers and class methods (for background tab info) in metamask-controller. * Adds getOriginOfCurrentTab selector * Adds IconWithFallback component and substitutes for appropriate cases * Add and utilize font mixins * Remove unused method in disconnect-all.container.js * Simplify buttonSizeLarge code in page-container-footer.component.js * Add and utilize getAccountsWithLabels selector * Remove console.log in ui/app/store/actions.js * Change last connected time format to yyyy-M-d * Fix css associated with IconWithFallback change * Ensure tracked openNonMetamaskTabsIDs are correctly set to inactive on tab changes * Code cleanup for LoginPerSite-ui * Use reusable function for modifying openNonMetamaskTabsIDs in background.js * Enables automatic switching to connected account when connected domain is open * Prevent exploit of tabIdOriginMap in background.js * Remove unneeded code from contentscript.js * Simplify current tab origin and window opener logic using remotePort listener tabs.queryTabs * Design and styling fixes for LoginPerSite-ui * Fix permissionHistory and permission logging for eth_requestAccounts and eth_accounts * Front end changes to support display of lastConnected time in connected and permissions screens * Fix lint errors * Refactor structure of permissionsHistory * Fix default values and object modifications for domain and permissionsHistory related data * Fix connecting to new accounts from modal * Replace retweet.svg with connect-white.svg * Fix signature-request.spec * Update metamask-inpage-provider version * Fix permissions e2e tests * Remove unneeded delay from test/e2e/signature-request.spec.js * Add delay before attempting to retrieve network id in dapp in ethereum-on=.spec * Use requestAccountTabIds strategy for determining tab id that opened a given window * Improve default values for permissions requests * Add some message descriptions to app/_locales/en/messages.json * Code clean up in permission controller * Stopped deep cloning object in mapObjectValues * Bump metamask-inpage-provider version * Add missing description in app/_locales/en/messages.json * Return promises from queryTabs and switchToTab of extension.js * Remove unused getAllPermissions function * Use default props in icon-with-fallback.component.js * Stop passing to permissions controller * Delete no longer used clear-approved-origins modal code * Remove duplicate imports in ui/app/components/app/index.scss * Use URL instead of regex in getOriginFromUrl() * Add runtime error checking to platform, promise based extension.tab methods * Support permission requests from external extensions * Improve font size and colour of the domain origin on the permission confirmation screen * Add support for toggling permissions * Ensure getRenderablePermissionsDomains only returns domains with exposedAccount caveat permissions * Remove unused code from LoginPerSite-ui branch * Ensure modal closes on Enter press for new-account-modal.component.js * Lint fix * fixup! Login Per Site UI (#7368) * Some code cleanup for LoginPerSite * Adds UX for connecting to dapps via the connected sites screen (#7593) * Adds UX for connecting to dapps via the connected sites screen * Use openMetaMaskTabIds from background.js to determine if current active tab is MetaMask * Delete unused permissions controller methods * Fixes two small bugs in the LoginPerSite ui (#7595) * Restore `providerRequest` message translations (#7600) This message was removed, but it was replaced with a very similar message called `likeToConnect`. The only difference is that the new message has "MetaMask" in it. Preserving these messages without "MetaMask" is probably better than deleting them, so these messages have all been restored and renamed to `likeToConnect`. * Login per site no sitemetadata fix (#7610) * Support connected sites for which we have no site metadata. * Change property containing subtitle info often populated by origin to a more accurate of purpose name * Lint fix * Improve disconnection modal messages (#7612) * Improve disconnectAccountModalDescription and disconnectAllModalDescription messages * Update disconnectAccountModalDescription app/_locales/en/messages.json Co-Authored-By: Mark Stacey <markjstacey@gmail.com> * Improve disconnectAccount modal message clarity * Adds cancel button to the account selection screen of the permissions request flow (#7613) * Fix eth_accounts permission language & selectability (#7614) * fix eth_accounts language & selectability * fix MetaMask capitalization in all messages * Close sidebar when opening connected sites (#7611) The 'Connected Sites' button in the accounts details now closes the sidebar, if it is open. This was accomplished by pulling the click handler for that button up to the wallet view component, where another button already followed a similar pattern of closing the sidebar. It seemed confusing to me that one handler was in the `AccountsDetails` container component, and one was handed down from above, so I added PropTypes to the container component. I'm not sure that the WalletView component is the best place for this logic, but I've put it there for now to be consistent with the add token button. * Reject permissions request upon tab close (#7618) Permissions requests are now rejected when the page is closed. This only applies to the full-screen view, as that is the view permission requests should be handled in. The case where the user deals with the request through a different view is handled in #7617 * Handle tab update failure (#7619) `extension.tabs.update` can sometimes fail if the user interacts with the tabs directly around the same time. The redirect flow has been updated to ensure that the permissions tab is still closed in that case. The user is on their own to find the dapp tab again in that case. * Login per site tab popup fixes (#7617) * Handle redirect in response to state update in permissions-connect * Ensure origin is available to permissions-connect subcomponents during redirect * Hide app bar whenever on redirect route * Improvements to handling of redirects in permissions-connect * Ensure permission request id change handling only happens when page is not null * Lint fix * Decouple confirm transaction screen from the selected address (#7622) * Avoid race condtion that could prevent contextual account switching (#7623) There was a race condition in the logic responsible for switching the selected account based upon the active tab. It was asynchronously querying the active tab, then assuming it had been retrieved later. The active tab info itself was already in the redux store in another spot, one that is guaranteed to be set before the UI renders. The race condition was avoided by deleting the duplicate state, and using the other active tab state. * Only redirect back to dapp if current tab is active (#7621) The "redirect back to dapp" behaviour can be disruptive when the permissions connect tab is not active. The purpose of the redirect was to maintain context between the dapp and the permissions request, but if the user has already moved to another tab, that no longer applies. * Fix JSX style lint errors * Remove unused state
5 years ago
await driver.waitUntilXWindowHandles(2);
await driver.switchToWindow(dapp);
await driver.delay(regularDelayMs);
});
it('adds multiple transactions', async function () {
const send3eth = await driver.findClickableElement({
text: 'Send',
tag: 'button',
});
await send3eth.click();
await driver.delay(largeDelayMs);
const contractDeployment = await driver.findClickableElement({
text: 'Deploy Contract',
tag: 'button',
});
await contractDeployment.click();
await driver.delay(largeDelayMs);
await send3eth.click();
await driver.delay(largeDelayMs);
await contractDeployment.click();
await driver.delay(largeDelayMs);
await driver.switchToWindow(extension);
await driver.delay(regularDelayMs);
await driver.clickElement('[data-testid="home__activity-tab"]');
await driver.clickElement('.transaction-list-item');
await driver.delay(largeDelayMs);
});
it('navigates the transactions', async function () {
await driver.clickElement('[data-testid="next-page"]');
let navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
let navigationText = await navigationElement.getText();
assert.equal(
navigationText.includes('2'),
true,
'changed transaction right',
);
await driver.clickElement('[data-testid="next-page"]');
navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
navigationText = await navigationElement.getText();
assert.equal(
navigationText.includes('3'),
true,
'changed transaction right',
);
await driver.clickElement('[data-testid="next-page"]');
navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
navigationText = await navigationElement.getText();
assert.equal(
navigationText.includes('4'),
true,
'changed transaction right',
);
await driver.clickElement('[data-testid="first-page"]');
navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
navigationText = await navigationElement.getText();
assert.equal(
navigationText.includes('1'),
true,
'navigate to first transaction',
);
await driver.clickElement('[data-testid="last-page"]');
navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
navigationText = await navigationElement.getText();
assert.equal(
navigationText.split('4').length,
3,
'navigate to last transaction',
);
await driver.clickElement('[data-testid="previous-page"]');
navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
navigationText = await navigationElement.getText();
assert.equal(
navigationText.includes('3'),
true,
'changed transaction left',
);
await driver.clickElement('[data-testid="previous-page"]');
navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
navigationText = await navigationElement.getText();
assert.equal(
navigationText.includes('2'),
true,
'changed transaction left',
);
});
it('adds a transaction while confirm screen is in focus', async function () {
let navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
let navigationText = await navigationElement.getText();
assert.equal(
navigationText.includes('2'),
true,
'second transaction in focus',
);
await driver.switchToWindow(dapp);
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Send', tag: 'button' });
await driver.delay(regularDelayMs);
await driver.switchToWindow(extension);
await driver.delay(regularDelayMs);
navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
navigationText = await navigationElement.getText();
assert.equal(
navigationText.includes('2'),
true,
'correct (same) transaction in focus',
);
});
it('rejects a transaction', async function () {
await driver.delay(tinyDelayMs);
await driver.clickElement({ text: 'Reject', tag: 'button' });
await driver.delay(largeDelayMs * 2);
const navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
await driver.delay(tinyDelayMs);
const navigationText = await navigationElement.getText();
assert.equal(navigationText.includes('4'), true, 'transaction rejected');
});
it('confirms a transaction', async function () {
await driver.delay(tinyDelayMs / 2);
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.delay(regularDelayMs);
const navigationElement = await driver.findElement(
'.confirm-page-container-navigation',
);
await driver.delay(tinyDelayMs / 2);
const navigationText = await navigationElement.getText();
await driver.delay(tinyDelayMs / 2);
assert.equal(navigationText.includes('3'), true, 'transaction confirmed');
});
it('rejects the rest of the transactions', async function () {
await driver.clickElement({ text: 'Reject 3', tag: 'a' });
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Reject All', tag: 'button' });
await driver.delay(largeDelayMs * 2);
await driver.wait(async () => {
const confirmedTxes = await driver.findElements(
'.transaction-list__completed-transactions .transaction-list-item',
);
return confirmedTxes.length === 1;
}, 10000);
});
});
describe('Add a custom token from a dapp', function () {
it('creates a new token', async function () {
let windowHandles = await driver.getAllWindowHandles();
const extension = windowHandles[0];
const dapp = windowHandles[1];
await driver.delay(regularDelayMs * 2);
await driver.switchToWindow(dapp);
await driver.delay(regularDelayMs * 2);
await driver.clickElement({ text: 'Create Token', tag: 'button' });
windowHandles = await driver.waitUntilXWindowHandles(3);
const popup = windowHandles[2];
await driver.switchToWindow(popup);
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Edit', tag: 'button' }, 10000);
const inputs = await driver.findElements('input[type="number"]');
const gasLimitInput = inputs[0];
const gasPriceInput = inputs[1];
await gasLimitInput.fill('4700000');
await gasPriceInput.fill('20');
await driver.delay(1000);
await driver.clickElement({ text: 'Save', tag: 'button' }, 10000);
await driver.clickElement({ text: 'Confirm', tag: 'button' }, 10000);
await driver.delay(regularDelayMs);
await driver.switchToWindow(dapp);
await driver.delay(tinyDelayMs);
const tokenContractAddress = await driver.waitForSelector({
css: '#tokenAddress',
text: '0x',
});
tokenAddress = await tokenContractAddress.getText();
await driver.delay(regularDelayMs);
await driver.closeAllWindowHandlesExcept([extension, dapp]);
await driver.delay(regularDelayMs);
await driver.switchToWindow(extension);
await driver.delay(largeDelayMs);
});
it('clicks on the Add Token button', async function () {
await driver.clickElement(`[data-testid="home__asset-tab"]`);
await driver.clickElement({ text: 'Add Token', tag: 'button' });
await driver.delay(regularDelayMs);
});
it('picks the newly created Test token', async function () {
await driver.clickElement({
text: 'Custom Token',
tag: 'button',
});
await driver.delay(regularDelayMs);
await driver.fill('#custom-address', tokenAddress);
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Next', tag: 'button' });
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Add Tokens', tag: 'button' });
await driver.delay(regularDelayMs);
});
it('renders the balance for the new token', async function () {
await driver.waitForSelector({
css: '.wallet-overview .token-overview__primary-balance',
text: '10 TST',
});
await driver.delay(regularDelayMs);
});
});
describe('Send token from inside MetaMask', function () {
it('starts to send a transaction', async function () {
await driver.clickElement('[data-testid="eth-overview-send"]');
await driver.delay(regularDelayMs);
await driver.fill(
'input[placeholder="Search, public address (0x), or ENS"]',
'0x2f318C334780961FB129D2a6c30D0763d9a5C970',
);
Address book send plus contact list (#6914) * Style Send Header * Move Send to-row to send view and restyle * Add "Recents" group to select recipient view * Rename SendToRow to AddRecipient * Basic UI and Layout * New ENSInput component * wip - fuzzy search for input * small refactor * Add Dialog * contact list initial * initial error on invalid address * clean up edit * Click to open modal * Create AddToAddressBookModal component * Modal styling and layout * modal i18n * Add to Addressbook * ens wip * ens wip * ENS Resolution * Reset input * Send to explicit address * Happy Path Complete * Add back error checking * Reset send-to when emptying input * Add back warning object * Fix linter * Fix unit test #1 - fix import paths * Remove dead tests * One more to go * Fix all unit tests * add unit test for reducers and actions * test rendering AddRecipient * Add tests for dialog boxes in AddRecipient * Add test for validating * Fix linter * Fix e2e tests * Token send e2e fix * Style View Contact * Style edit-contact * Fix e2e * Fix from-import-beta-ui e2e spec * Make section header say "add recipient” by default * Auto-focus add recipient input * Update placeholder text * Update input title font size * Auto advance to next step if user paste a valid address * Ellipsify address when recipient is selected * Fix app header background color on desktop * Give each form row a margin of 16px * Use .container/.component naming pattern for ens-input * Auto-focus on input when add to addressbook modal is opened; Save on Enter * Fix and add unit test * Fix selectors name in e2e tests * Correct e2e test token amount for address-book-send changes * Adds e2e test for editing a transaction * Delete test/integration/lib/send-new-ui.js * Add tests for amount max button and high value error on send screen to test/e2e/metamask-ui.spec.js * lint and revert to address as object keys * add chainId based on current network to address book entry * fix test * only display contacts for the current network * Improve ENS message when not found on current network * Add error to indicate when network does not support ENS * bump gaba * address book, resolve comments * Move contact-list to its own component * De-duplicate getaddressbook selector and refactor name selection logic in contact-list-tab/ * Use contact-list component in contact-list-tab.component (i.e. in settings) * Improve/fix settings headers for popup and browser views * Lint fixes related to address book updates * Add 'My accounts' page to settings address book * Update add new contact button in settings to match floating circular design * Improve styles of view contact page * Improve styles and labels of the add-contact.component * Further lint fixes related to address book updates * Update unit tests as per address book updates * Ensure that contact list groups are sorted alphabetically * Refactor settings component to use a container for connection to redux; allow display of addressbook name in settings header * Decouple ens-input.component from send context * Add ens resolution to add contact screen in settings * Switching networks when an ens address is shown on send form removes the ens address. * Resolve send screen search for ensAddress to matching address book entry if it exists * Show resolved ens icon and address if exists (settings: add-contact.component) * Make the displayed and copied address in view-contact.component the checksummed address * Default alias state prop in AddToAddressBookModal to empty string * Use keyCode to detect enter key in AddToAddressBookModal * Ensure add-contact component properly updates after QR code detection * Fix display of all recents after clicking 'Load More' in contact list * Fix send screen contact searching after network switching * Code cleanup related to address book changes * Update unit tests for address book changes * Update ENS name not found on network message * Add ens registration error message * Cancel on edit mode takes user back to view screen * Adds support for memo to settings contact list view and edit screens * Modify designs of edit and view contact in popup environment * Update settings content list UX to show split columns in fullscreen and proper internal navigation * Correct background address book API usages in UI
5 years ago
driver.fill('.unit-input__input', '1');
});
it('transitions to the confirm screen', async function () {
// Continue to next screen
await driver.delay(largeDelayMs);
await driver.clickElement({ text: 'Next', tag: 'button' });
await driver.delay(regularDelayMs);
});
it('displays the token transfer data', async function () {
await driver.clickElement({ text: 'Data', tag: 'button' });
await driver.delay(regularDelayMs);
const functionType = await driver.findElement(
'.confirm-page-container-content__function-type',
);
const functionTypeText = await functionType.getText();
assert.equal(functionTypeText, 'Transfer');
const tokenAmount = await driver.findElement(
'.confirm-page-container-summary__title-text',
);
const tokenAmountText = await tokenAmount.getText();
assert.equal(tokenAmountText, '1 TST');
const confirmDataDiv = await driver.findElement(
'.confirm-page-container-content__data-box',
);
const confirmDataText = await confirmDataDiv.getText();
await driver.delay(regularDelayMs);
assert(
confirmDataText.match(
/0xa9059cbb0000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c97/u,
),
);
await driver.clickElement({ text: 'Details', tag: 'button' });
await driver.delay(regularDelayMs);
});
it('customizes gas', async function () {
await driver.clickElement({ text: 'Edit', tag: 'button' });
await driver.delay(largeDelayMs);
const inputs = await driver.findElements('input[type="number"]');
const gasLimitInput = inputs[0];
const gasPriceInput = inputs[1];
await gasLimitInput.fill('100000');
await gasPriceInput.fill('100');
await driver.delay(1000);
await driver.clickElement({ text: 'Save', tag: 'button' }, 10000);
});
it('submits the transaction', async function () {
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.delay(regularDelayMs);
});
it('finds the transaction in the transactions list', async function () {
await driver.waitForSelector(
{
css:
'.transaction-list__completed-transactions .transaction-list-item__primary-currency',
text: '-1 TST',
},
{ timeout: 10000 },
);
Cleanup beforeunload handler after transaction is resolved (#7333) * Cleanup beforeunload handler after transaction is resolved The notification window was updated to reject transactions upon close in #6340. A handler that rejects the transaction was added to `window.onbeforeunload`, and it was cleared in `actions.js` if it was confirmed or rejected. However, the `onbeforeunload` handler remained uncleared if the transaction was resolved in another window. This results in the transaction being rejected when the notification window closes, even long after the transaction is submitted and confirmed. This has been the cause of many problems with the Firefox e2e tests. Instead the `onbeforeunload` handler is cleared in the `componentWillUnmount` lifecycle function, alongside where it's set in the first place. This ensures that it's correctly unset regardless of how the transaction was resolved, and it better matches user expectations. * Fix indentation and remove redundant export The `run-all.sh` Bash script now uses consistent indentation, and is consistent about only re-exporting the Ganache arguments when they change. * Ensure transactions are completed before checking balance Various intermittent e2e test failures appear to be caused by React re-rendering the transaction list during the test, as the transaction goes from pending to confirmed. To avoid this race condition, the transaction is now explicitly looked for in the confirmed transaction list in each of the tests using this pattern. * Enable all e2e tests on Firefox The remaining tests that were disabled on Firefox now work correctly. Only a few timing adjustments were needed. * Update Firefox used in CI Firefox v70 is now used on CI instead of v68. This necessitated rewriting the function where the extension ID was obtained because the Firefox extensions page was redesigned.
5 years ago
await driver.waitForSelector({
css: '.list-item__heading',
text: 'Send TST',
});
});
});
describe('Send a custom token from dapp', function () {
it('sends an already created token', async function () {
const windowHandles = await driver.getAllWindowHandles();
const extension = windowHandles[0];
const dapp = await driver.switchToWindowWithTitle(
'E2E Test Dapp',
windowHandles,
);
await driver.delay(regularDelayMs);
await driver.switchToWindow(dapp);
await driver.delay(tinyDelayMs);
await driver.clickElement({ text: 'Transfer Tokens', tag: 'button' });
await driver.switchToWindow(extension);
await driver.delay(largeDelayMs);
await driver.findElements('.transaction-list__pending-transactions');
await driver.waitForSelector(
{
css: '.transaction-list-item__primary-currency',
text: '-1.5 TST',
},
{ timeout: 10000 },
);
await driver.clickElement('.transaction-list-item__primary-currency');
await driver.delay(regularDelayMs);
const transactionAmounts = await driver.findElements(
'.currency-display-component__text',
);
const transactionAmount = transactionAmounts[0];
assert(await transactionAmount.getText(), '1.5 TST');
});
it('customizes gas', async function () {
await driver.clickElement({ text: 'Edit', tag: 'button' });
await driver.delay(largeDelayMs);
await driver.clickElement(
{ text: 'Edit suggested gas fee', tag: 'button' },
10000,
);
await driver.delay(1000);
const inputs = await driver.findElements('input[type="number"]');
const gasLimitInput = inputs[0];
const gasPriceInput = inputs[1];
await gasLimitInput.fill('60000');
await gasPriceInput.fill('10');
await driver.delay(1000);
await driver.clickElement({ text: 'Save', tag: 'button' }, 10000);
await driver.findElement({ tag: 'span', text: '0.0006' });
});
it('submits the transaction', async function () {
const tokenAmount = await driver.findElement(
'.confirm-page-container-summary__title-text',
);
const tokenAmountText = await tokenAmount.getText();
assert.equal(tokenAmountText, '1.5 TST');
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.delay(regularDelayMs);
});
it('finds the transaction in the transactions list', async function () {
await driver.waitForSelector({
css:
'.transaction-list__completed-transactions .transaction-list-item__primary-currency',
text: '-1.5 TST',
});
await driver.waitForSelector({
css: '.list-item__heading',
text: 'Send TST',
});
});
it('checks balance', async function () {
await driver.clickElement({
text: 'Assets',
tag: 'button',
});
await driver.waitForSelector({
css: '.asset-list-item__token-button',
text: '7.5 TST',
});
await driver.clickElement({
text: 'Activity',
tag: 'button',
});
});
});
describe('Approves a custom token from dapp', function () {
it('approves an already created token', async function () {
const windowHandles = await driver.getAllWindowHandles();
const extension = windowHandles[0];
const dapp = await driver.switchToWindowWithTitle(
'E2E Test Dapp',
windowHandles,
);
await driver.closeAllWindowHandlesExcept([extension, dapp]);
await driver.delay(regularDelayMs);
await driver.switchToWindow(dapp);
await driver.delay(tinyDelayMs);
await driver.clickElement({ text: 'Approve Tokens', tag: 'button' });
await driver.switchToWindow(extension);
await driver.delay(regularDelayMs);
await driver.wait(async () => {
const pendingTxes = await driver.findElements(
'.transaction-list__pending-transactions .transaction-list-item',
);
return pendingTxes.length === 1;
}, 10000);
6 years ago
await driver.waitForSelector({
// Selects only the very first transaction list item immediately following the 'Pending' header
css:
'.transaction-list__pending-transactions .transaction-list__header + .transaction-list-item .list-item__heading',
text: 'Approve TST spend limit',
});
await driver.clickElement('.transaction-list-item');
await driver.delay(regularDelayMs);
});
it('displays the token approval data', async function () {
await driver.clickElement(
'.confirm-approve-content__view-full-tx-button',
);
await driver.delay(regularDelayMs);
const functionType = await driver.findElement(
'.confirm-approve-content__data .confirm-approve-content__small-text',
);
const functionTypeText = await functionType.getText();
assert.equal(functionTypeText, 'Function: Approve');
const confirmDataDiv = await driver.findElement(
'.confirm-approve-content__data__data-block',
);
const confirmDataText = await confirmDataDiv.getText();
assert(
confirmDataText.match(
/0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef4/u,
),
);
});
it('customizes gas', async function () {
await driver.clickElement('.confirm-approve-content__small-blue-text');
await driver.delay(regularDelayMs);
await driver.clickElement(
{ text: 'Edit suggested gas fee', tag: 'button' },
10000,
);
await driver.delay(regularDelayMs);
const [gasLimitInput, gasPriceInput] = await driver.findElements(
'input[type="number"]',
);
await gasPriceInput.fill('10');
await driver.delay(50);
await gasLimitInput.fill('60001');
Use `AdvancedGasInputs` in `AdvancedTabContent` (#7186) * Use `AdvancedGasInputs` in `AdvancedTabContent` The `AdvancedGasInputs` component was originally extracted from the `AdvancedTabContent` component, duplicating much of the rendering logic. They have since evolved separately, with bugs being fixed in one place but not the other. The inputs and outputs expected weren't exactly the same, as the `AdvancedGasInputs` component converts the input custom gas price and limit, and it converts them both in the setter methods as well. The `GasModalPageContainer` had to be adjusted to avoid converting these values multiple times. Both components dealt with input debouncing separately, both in less than ideal ways. `AdvancedTabContent` didn't debounce either field, but it did debounce the check for whether the gas limit field was below the minimum value. So if a less-than-minimum value was set, it would be propogated upwards and could be saved if the user clicked 'Save' quickly enough. After a second delay it would snap back to the minimum value. The `AdvancedGasInputs` component debounced both fields, but it would replace any gas limit below the minimum with the minimum value. This led to a problem where a brief pause during typing would reset the field to 21000. The `AdvancedGasInputs` approach was chosen, except that it was updated to no longer change the gas limit if it was below the minimum. Instead it displays an error. Parent components were checked to ensure they would detect the error case of the gas limit being set too low, and prevent the form submission in those cases. Of the three parents, one had already dealt with it correctly, one needed to convert the gas limit from hex first, and another needed the gas limit check added. Closes #6872 * Cleanup send components Empty README files have been removed, and a mistake in the index file for the send page has been corrected. The Gas Slider component class name was updated as well; it looks like it was originally created from `AdvancedTabContent`, so it still had that class name.
5 years ago
await driver.delay(1000);
await driver.clickElement({ text: 'Save', tag: 'button' }, 10000);
const gasFeeInEth = await driver.findElement(
'.confirm-approve-content__transaction-details-content__secondary-fee',
);
assert.equal(await gasFeeInEth.getText(), '0.0006 ETH');
});
it('edits the permission', async function () {
const editButtons = await driver.findClickableElements(
'.confirm-approve-content__small-blue-text',
);
await editButtons[2].click();
// wait for permission modal to be visible
const permissionModal = await driver.findVisibleElement('span .modal');
const radioButtons = await driver.findClickableElements(
'.edit-approval-permission__edit-section__radio-button',
);
await radioButtons[1].click();
await driver.fill('input', '5');
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Save', tag: 'button' });
// wait for permission modal to be removed from DOM.
await permissionModal.waitForElementState('hidden');
const permissionInfo = await driver.findElements(
'.confirm-approve-content__medium-text',
);
const amountDiv = permissionInfo[0];
assert.equal(await amountDiv.getText(), '5 TST');
});
it('submits the transaction', async function () {
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.delay(regularDelayMs);
});
it('finds the transaction in the transactions list', async function () {
await driver.waitForSelector({
// Select only the heading of the first entry in the transaction list.
css:
'.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
text: 'Approve TST spend limit',
});
});
});
describe('Transfers a custom token from dapp when no gas value is specified', function () {
it('transfers an already created token, without specifying gas', async function () {
const windowHandles = await driver.getAllWindowHandles();
const extension = windowHandles[0];
const dapp = await driver.switchToWindowWithTitle(
'E2E Test Dapp',
windowHandles,
);
await driver.closeAllWindowHandlesExcept([extension, dapp]);
await driver.delay(regularDelayMs);
await driver.switchToWindow(dapp);
await driver.clickElement({
text: 'Transfer Tokens Without Gas',
tag: 'button',
});
await driver.switchToWindow(extension);
await driver.delay(regularDelayMs);
await driver.wait(async () => {
const pendingTxes = await driver.findElements(
'.transaction-list__pending-transactions .transaction-list-item',
);
return pendingTxes.length === 1;
}, 10000);
await driver.waitForSelector({
css: '.transaction-list-item__primary-currency',
text: '-1.5 TST',
});
await driver.clickElement('.transaction-list-item');
await driver.delay(regularDelayMs);
});
it('submits the transaction', async function () {
await driver.delay(largeDelayMs * 2);
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.delay(largeDelayMs * 2);
});
it('finds the transaction in the transactions list', async function () {
await driver.waitForSelector({
// Select the heading of the first transaction list item in the
// completed transaction list with text matching Send TST
css:
'.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
text: 'Send TST',
});
await driver.waitForSelector({
css:
'.transaction-list__completed-transactions .transaction-list-item:first-child .transaction-list-item__primary-currency',
text: '-1.5 TST',
});
});
});
describe('Approves a custom token from dapp when no gas value is specified', function () {
it('approves an already created token', async function () {
const windowHandles = await driver.getAllWindowHandles();
const extension = windowHandles[0];
const dapp = await driver.switchToWindowWithTitle(
'E2E Test Dapp',
windowHandles,
);
await driver.closeAllWindowHandlesExcept([extension, dapp]);
await driver.delay(regularDelayMs);
await driver.switchToWindow(dapp);
await driver.delay(tinyDelayMs);
await driver.clickElement({
text: 'Approve Tokens Without Gas',
tag: 'button',
});
await driver.switchToWindow(extension);
await driver.delay(regularDelayMs);
await driver.wait(async () => {
const pendingTxes = await driver.findElements(
'.transaction-list__pending-transactions .transaction-list-item',
);
return pendingTxes.length === 1;
}, 10000);
await driver.waitForSelector({
// Selects only the very first transaction list item immediately following the 'Pending' header
css:
'.transaction-list__pending-transactions .transaction-list__header + .transaction-list-item .list-item__heading',
text: 'Approve TST spend limit',
});
await driver.clickElement('.transaction-list-item');
await driver.delay(regularDelayMs);
});
it('shows the correct recipient', async function () {
await driver.clickElement(
'.confirm-approve-content__view-full-tx-button',
);
await driver.delay(regularDelayMs);
const permissionInfo = await driver.findElements(
'.confirm-approve-content__medium-text',
);
const recipientDiv = permissionInfo[1];
assert.equal(await recipientDiv.getText(), '0x2f318C33...C970');
});
it('submits the transaction', async function () {
await driver.delay(1000);
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.delay(regularDelayMs);
});
it('finds the transaction in the transactions list', async function () {
await driver.waitForSelector({
css:
'.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
text: 'Approve TST spend limit',
});
});
});
});