diff --git a/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap b/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap
index c6fa6d08a..86163faaf 100644
--- a/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap
+++ b/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap
@@ -3,15 +3,213 @@
exports[`App Header should match snapshot 1`] = `
+
+
+
+
+ Test Account
+
+
+
+
diff --git a/ui/components/multichain/app-header/app-header.js b/ui/components/multichain/app-header/app-header.js
index 081ed2a1b..bf530f3b9 100644
--- a/ui/components/multichain/app-header/app-header.js
+++ b/ui/components/multichain/app-header/app-header.js
@@ -105,17 +105,17 @@ export const AppHeader = ({ location }) => {
// Disable the network and account pickers if the user is in
// a critical flow
const sendStage = useSelector(getSendStage);
+ const isTransactionEditPage = [
+ SEND_STAGES.EDIT,
+ SEND_STAGES.DRAFT,
+ SEND_STAGES.ADD_RECIPIENT,
+ ].includes(sendStage);
const isConfirmationPage = Boolean(
matchPath(location.pathname, {
path: CONFIRM_TRANSACTION_ROUTE,
exact: false,
}),
);
- const isTransactionEditPage = [
- SEND_STAGES.EDIT,
- SEND_STAGES.DRAFT,
- SEND_STAGES.ADD_RECIPIENT,
- ].includes(sendStage);
const isSwapsPage = Boolean(
matchPath(location.pathname, { path: SWAPS_ROUTE, exact: false }),
);
@@ -123,11 +123,18 @@ export const AppHeader = ({ location }) => {
matchPath(location.pathname, { path: BUILD_QUOTE_ROUTE, exact: false }),
);
- const disablePickers =
- isConfirmationPage ||
+ const hasUnapprovedTransactions = useSelector(
+ (state) => Object.keys(state.metamask.unapprovedTxs).length > 0,
+ );
+
+ const disableAccountPicker =
+ isConfirmationPage || (isSwapsPage && !isSwapsBuildQuotePage);
+
+ const disableNetworkPicker =
+ isSwapsPage ||
isTransactionEditPage ||
- (isSwapsPage && !isSwapsBuildQuotePage);
- const disableNetworkPicker = isSwapsPage || disablePickers;
+ isConfirmationPage ||
+ hasUnapprovedTransactions;
// Callback for network dropdown
const networkOpenCallback = useCallback(() => {
@@ -261,7 +268,7 @@ export const AppHeader = ({ location }) => {
},
});
}}
- disabled={disablePickers}
+ disabled={disableAccountPicker}
/>
) : null}
{
+ const store = configureStore({
+ ...mockState,
+ activeTab: {
+ origin: 'https://remix.ethereum.org',
+ },
+ ...stateChanges,
+ });
+ return renderWithProvider(, store);
+};
+
describe('App Header', () => {
it('should match snapshot', () => {
- const mockState = {
- activeTab: {
- title: 'Eth Sign Tests',
- origin: 'https://remix.ethereum.org',
- protocol: 'https:',
- url: 'https://remix.ethereum.org/',
- },
- metamask: {
- providerConfig: {
- chainId: CHAIN_IDS.GOERLI,
- },
- accounts: {
- '0x7250739de134d33ec7ab1ee592711e15098c9d2d': {
- address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d',
- },
- '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5': {
- address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5',
- },
- },
- preferences: {
- showTestNetworks: true,
- },
- selectedAddress: '0x7250739de134d33ec7ab1ee592711e15098c9d2d',
- cachedBalances: {},
- subjects: {
- 'https://remix.ethereum.org': {
- permissions: {
- eth_accounts: {
- caveats: [
- {
- type: 'restrictReturnedAccounts',
- value: [
- '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5',
- '0x7250739de134d33ec7ab1ee592711e15098c9d2d',
- ],
- },
- ],
- date: 1586359844177,
- id: '3aa65a8b-3bcb-4944-941b-1baa5fe0ed8b',
- invoker: 'https://remix.ethereum.org',
- parentCapability: 'eth_accounts',
- },
- },
- },
- 'peepeth.com': {
- permissions: {
- eth_accounts: {
- caveats: [
- {
- type: 'restrictReturnedAccounts',
- value: ['0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5'],
- },
- ],
- date: 1585676177970,
- id: '840d72a0-925f-449f-830a-1aa1dd5ce151',
- invoker: 'peepeth.com',
- parentCapability: 'eth_accounts',
- },
- },
- },
- },
- identities: {
- '0x7250739de134d33ec7ab1ee592711e15098c9d2d': {
- address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d',
- name: 'Really Long Name That Should Be Truncated',
- },
- '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5': {
- address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5',
- lastSelected: 1586359844192,
- name: 'Account 1',
- },
- },
- keyrings: [
- {
- accounts: [
- '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5',
- '0x7250739de134d33ec7ab1ee592711e15098c9d2d',
- ],
- },
- ],
- permissionHistory: {
- 'https://remix.ethereum.org': {
- eth_accounts: {
- accounts: {
- '0x7250739de134d33ec7ab1ee592711e15098c9d2d': 1586359844192,
- '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5': 1586359844192,
- },
- lastApproved: 1586359844192,
- },
- },
- },
- },
- appState: {
- onboardedInThisUISession: false,
- },
- send: {
- stage: SEND_STAGES.INACTIVE,
- },
- };
-
- const mockStore = configureStore();
- const store = mockStore(mockState);
- const { container } = renderWithProvider(
- ,
- store,
- );
+ const { container } = render();
expect(container).toMatchSnapshot();
});
+
+ it('should disable the network picker during a send', () => {
+ const { getByTestId } = render({ send: { stage: SEND_STAGES.DRAFT } });
+ expect(getByTestId('network-display')).toBeDisabled();
+ });
+
+ it('should allow switching accounts during a send', () => {
+ const { getByTestId } = render({ send: { stage: SEND_STAGES.DRAFT } });
+ expect(getByTestId('account-menu-icon')).toBeEnabled();
+ });
});
diff --git a/ui/components/multichain/global-menu/global-menu.js b/ui/components/multichain/global-menu/global-menu.js
index 57abdbb36..978ec4a1c 100644
--- a/ui/components/multichain/global-menu/global-menu.js
+++ b/ui/components/multichain/global-menu/global-menu.js
@@ -58,6 +58,10 @@ export const GlobalMenu = ({ closeMenu, anchorElement }) => {
const history = useHistory();
const metaMetricsId = useSelector(getMetaMetricsId);
+ const hasUnapprovedTransactions = useSelector(
+ (state) => Object.keys(state.metamask.unapprovedTxs).length > 0,
+ );
+
///: BEGIN:ONLY_INCLUDE_IN(snaps)
const unreadNotificationsCount = useSelector(getUnreadNotificationsCount);
///: END:ONLY_INCLUDE_IN
@@ -199,6 +203,7 @@ export const GlobalMenu = ({ closeMenu, anchorElement }) => {
diff --git a/ui/components/multichain/global-menu/global-menu.test.js b/ui/components/multichain/global-menu/global-menu.test.js
index 06fb33800..0f996a0ab 100644
--- a/ui/components/multichain/global-menu/global-menu.test.js
+++ b/ui/components/multichain/global-menu/global-menu.test.js
@@ -4,10 +4,11 @@ import configureStore from '../../../store/store';
import mockState from '../../../../test/data/mock-state.json';
import { GlobalMenu } from '.';
-const render = () => {
+const render = (metamaskStateChanges = {}) => {
const store = configureStore({
metamask: {
...mockState.metamask,
+ ...metamaskStateChanges,
},
});
return renderWithProvider(
@@ -52,6 +53,20 @@ describe('AccountListItem', () => {
});
});
+ it('disables the settings item when there is an active transaction', async () => {
+ const { getByTestId } = render();
+ await waitFor(() => {
+ expect(getByTestId('global-menu-settings')).toBeDisabled();
+ });
+ });
+
+ it('enables the settings item when there is no active transaction', async () => {
+ const { getByTestId } = render({ unapprovedTxs: {} });
+ await waitFor(() => {
+ expect(getByTestId('global-menu-settings')).toBeEnabled();
+ });
+ });
+
it('expands metamask to tab when item is clicked', async () => {
global.platform = { openExtensionInBrowser: jest.fn() };
diff --git a/ui/components/ui/menu/menu-item.js b/ui/components/ui/menu/menu-item.js
index 6e005e1ea..9e2913d12 100644
--- a/ui/components/ui/menu/menu-item.js
+++ b/ui/components/ui/menu/menu-item.js
@@ -12,11 +12,13 @@ const MenuItem = ({
iconName,
onClick,
subtitle,
+ disabled = false,
}) => (