Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pedronfigueiredo committed Jul 9, 2024
1 parent 341e2c7 commit 05e03d0
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 27 deletions.
1 change: 1 addition & 0 deletions app/scripts/controllers/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default class PreferencesController {
featureNotificationsEnabled: false,
showTokenAutodetectModal: null,
showNftAutodetectModal: null, // null because we want to show the modal only the first time
isConfirmationAdvancedDetailsOpen: false,
},
// ENS decentralized website resolution
ipfsGateway: IPFS_DEFAULT_GATEWAY_URL,
Expand Down
127 changes: 127 additions & 0 deletions app/scripts/migrations/122.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { UseNonceField } from '../../../ui/pages/confirmations/token-allowance/token-allowance.stories';
import PreferencesController from '../controllers/preferences';
import { migrate, version } from './122';

const oldVersion = 121;

describe('migration #122', () => {
it('updates the version metadata', async () => {
const oldStorage = {
meta: { version: oldVersion },
data: {},
};

const newStorage = await migrate(oldStorage);

expect(newStorage.meta).toStrictEqual({ version });
});

it('does nothing if no preferences controller state is set', async () => {
const oldState = {
OtherController: {},
};

const transformedState = await migrate({
meta: { version: oldVersion },
data: oldState,
});

expect(transformedState.data).toEqual(oldState);
});

it('does nothing if no preferences state is set', async () => {
const oldState = {
PreferencesController: {},
};

const transformedState = await migrate({
meta: { version: oldVersion },
data: oldState,
});

expect(transformedState.data).toEqual(oldState);
});

it('returns state with advanced details opened if `useNonceField` is enabled', async () => {
const initialState = {
PreferencesController: {
preferences: { isConfirmationAdvancedDetailsOpen: false },
},
metamask: {
useNonceField: true,
},
};
const transformedState = await migrate({
meta: { version: oldVersion },
data: initialState,
});

expect(transformedState).toEqual({
meta: { version: oldVersion + 1 },
data: {
...initialState,
PreferencesController: {
...initialState.PreferencesController,
preferences: { isConfirmationAdvancedDetailsOpen: true },
},
},
});
});

it('returns state with advanced details opened if `sendHexData` is enabled', async () => {
const initialState = {
PreferencesController: {
preferences: { isConfirmationAdvancedDetailsOpen: false },
},
metamask: {
featureFlags: {
sendHexData: true,
},
},
};
const transformedState = await migrate({
meta: { version: oldVersion },
data: initialState,
});

expect(transformedState).toEqual({
meta: { version: oldVersion + 1 },
data: {
...initialState,
PreferencesController: {
...initialState.PreferencesController,
preferences: { isConfirmationAdvancedDetailsOpen: true },
},
},
});
});

it('returns state with advanced details closed if `sendHexData` and `useNonceField` are disabled', async () => {
const initialState = {
PreferencesController: {
preferences: { isConfirmationAdvancedDetailsOpen: false },
},
metamask: {
useNonceField: false,
featureFlags: {
sendHexData: false,
},
},
};
const transformedState = await migrate({
meta: { version: oldVersion },
data: initialState,
});

expect(transformedState).toEqual({
meta: { version: oldVersion + 1 },
data: {
...initialState,
PreferencesController: {
...initialState.PreferencesController,
preferences: { isConfirmationAdvancedDetailsOpen: false },
},
},
});
});
});
53 changes: 53 additions & 0 deletions app/scripts/migrations/122.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { cloneDeep } from 'lodash';
import { hasProperty } from '@metamask/utils';

type VersionedData = {
meta: { version: number };
data: Record<string, unknown>;
};

export const version = 122;

/**
* This migration sets the preference `isConfirmationAdvancedDetailsOpen` to
* `true` if the user has enabled `useNonceField` or `sendHexData`.
*
* @param originalVersionedData - Versioned MetaMask extension state, exactly
* what we persist to dist.
* @param originalVersionedData.meta - State metadata.
* @param originalVersionedData.meta.version - The current state version.
* @param originalVersionedData.data - The persisted MetaMask state, keyed by
* controller.
* @returns Updated versioned MetaMask extension state.
*/
export async function migrate(
originalVersionedData: VersionedData,
): Promise<VersionedData> {
const versionedData = cloneDeep(originalVersionedData);
versionedData.meta.version = version;
transformState(versionedData.data);
return versionedData;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function transformState(state: Record<string, any>) {
if (
!hasProperty(state, 'PreferencesController') ||
!hasProperty(state.PreferencesController, 'preferences')
) {
return state;
}

const isCustomNonceFieldEnabled = state?.metamask?.useNonceField;
const isHexDataVisibilityEnabled = state?.metamask?.featureFlags?.sendHexData;

if (isCustomNonceFieldEnabled || isHexDataVisibilityEnabled) {
state.PreferencesController.preferences.isConfirmationAdvancedDetailsOpen =
true;
} else {
state.PreferencesController.preferences.isConfirmationAdvancedDetailsOpen =
false;
}

return state;
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ describe('Confirmation Redesign Contract Interaction Component', function () {
await confirmContractDeploymentTransaction(driver);

await createDepositTransaction(driver);

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
// re open advanced details
await toggleAdvancedDetails(driver);

await confirmDepositTransactionWithCustomNonce(driver, '10');
},
);
Expand Down Expand Up @@ -286,6 +291,8 @@ describe('Confirmation Redesign Contract Interaction Component', function () {

await driver.waitUntilXWindowHandles(3);
await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
// re open advanced details
await toggleAdvancedDetails(driver);

await assertAdvancedGasDetails(driver);
},
Expand Down Expand Up @@ -323,6 +330,8 @@ describe('Confirmation Redesign Contract Interaction Component', function () {

await driver.waitUntilXWindowHandles(3);
await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
// re open advanced details
await toggleAdvancedDetails(driver);

await assertAdvancedGasDetails(driver);
},
Expand Down
2 changes: 1 addition & 1 deletion ui/components/ui/info-tooltip/info-tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ InfoTooltip.propTypes = {
/**
* Text label that shows up after hover
*/
contentText: PropTypes.oneOf([PropTypes.string, PropTypes.node]),
contentText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/**
* Shows position of the tooltip
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ exports[`Header should match snapshot with transaction confirmation 1`] = `
</div>
</div>
<div
class="mm-box mm-box--background-color-info-muted mm-box--rounded-md"
class="mm-box mm-box--background-color-transparent mm-box--rounded-md"
>
<button
aria-label="Advanced tx details"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ const cases = [
const render = () => {
const store = configureStore(mockStore);
return renderWithProvider(
// eslint-disable-next-line no-empty-function
<AdvancedDetailsProvider>
<HeaderInfo />
</AdvancedDetailsProvider>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ const render = (storeOverrides = {}) => {
});

return renderWithProvider(
// eslint-disable-next-line no-empty-function
<AdvancedDetailsProvider>
<Header />
</AdvancedDetailsProvider>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import mockState from '../../../../../../../test/data/mock-state.json';
import { renderHookWithProvider } from '../../../../../../../test/lib/render-helpers';
import { useAdvancedDetailsHandler } from './advanced-details-context';
import {
AdvancedDetailsProvider,
useAdvancedDetailsHandler,
} from './advanced-details-context';

jest.mock('react', () => ({
...jest.requireActual('react'),
useContext: jest.fn(),
jest.mock('../../../../../../../ui/selectors/selectors.js', () => ({
...jest.requireActual('../../../../../../../ui/selectors/selectors.js'),
getConfirmationAdvancedDetailsOpen: jest.fn(),
}));

jest.mock('../../../../../../store/actions.ts', () => ({
...jest.requireActual('../../../../../../store/actions.ts'),
setConfirmationAdvancedDetailsOpen: jest.fn(),
}));

describe('useAdvancedDetailsHandler', () => {
Expand All @@ -17,4 +26,42 @@ describe('useAdvancedDetailsHandler', () => {
),
);
});

it('showAdvancedDetails is false based on Redux state', () => {
const getConfirmationAdvancedDetailsOpenMock =
require('../../../../../../../ui/selectors/selectors.js').getConfirmationAdvancedDetailsOpen;
const setConfirmationAdvancedDetailsOpenMock =
require('../../../../../../store/actions.ts').setConfirmationAdvancedDetailsOpen;

getConfirmationAdvancedDetailsOpenMock.mockReturnValue(false);
setConfirmationAdvancedDetailsOpenMock.mockReturnValue(() => {});

const { result } = renderHookWithProvider(
() => useAdvancedDetailsHandler(),
mockState,
'/',
AdvancedDetailsProvider,
);

expect(result.current.showAdvancedDetails).toBe(false);
});

it('showAdvancedDetails is true based on Redux state', () => {
const getConfirmationAdvancedDetailsOpenMock =
require('../../../../../../../ui/selectors/selectors.js').getConfirmationAdvancedDetailsOpen;
const setConfirmationAdvancedDetailsOpenMock =
require('../../../../../../store/actions.ts').setConfirmationAdvancedDetailsOpen;

getConfirmationAdvancedDetailsOpenMock.mockReturnValue(true);
setConfirmationAdvancedDetailsOpenMock.mockReturnValue(() => {});

const { result } = renderHookWithProvider(
() => useAdvancedDetailsHandler(),
mockState,
'/',
AdvancedDetailsProvider,
);

expect(result.current.showAdvancedDetails).toBe(true);
});
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import React, {
ReactElement,
createContext,
useContext,
useMemo,
useState,
} from 'react';
import { useSelector } from 'react-redux';
import { getSendHexDataFeatureFlagState } from '../../../../../../ducks/metamask/metamask';
import { getUseNonceField } from '../../../../../../selectors';
import React, { ReactElement, createContext, useContext, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getConfirmationAdvancedDetailsOpen } from '../../../../../../selectors';
import { setConfirmationAdvancedDetailsOpen } from '../../../../../../store/actions';

type AdvancedDetailsHandlerContextType = {
showAdvancedDetails: boolean;
Expand All @@ -21,18 +15,15 @@ export const AdvancedDetailsHandlerContext = createContext<
export const AdvancedDetailsProvider: React.FC<{
children: ReactElement;
}> = ({ children }) => {
const enableCustomNonce = useSelector(getUseNonceField);
const showHexData = useSelector(getSendHexDataFeatureFlagState);
const dispatch = useDispatch();

const [showAdvancedDetails, setShowAdvancedDetails] = useState(
enableCustomNonce || showHexData,
);
const showAdvancedDetails = useSelector(getConfirmationAdvancedDetailsOpen);
const setShowAdvancedDetails = (value: boolean): void => {
dispatch(setConfirmationAdvancedDetailsOpen(value));
};

const advancedDetailsObject = useMemo(
() => ({
showAdvancedDetails,
setShowAdvancedDetails,
}),
() => ({ showAdvancedDetails, setShowAdvancedDetails }),
[showAdvancedDetails, setShowAdvancedDetails],
);

Expand Down
5 changes: 5 additions & 0 deletions ui/selectors/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2529,6 +2529,11 @@ export function getSnapsInstallPrivacyWarningShown(state) {
return snapsInstallPrivacyWarningShown;
}

export function getConfirmationAdvancedDetailsOpen(state) {
const { isConfirmationAdvancedDetailsOpen } = getPreferences(state);
return Boolean(isConfirmationAdvancedDetailsOpen);
}

///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
export function getsnapsAddSnapAccountModalDismissed(state) {
const { snapsAddSnapAccountModalDismissed } = state.metamask;
Expand Down
4 changes: 4 additions & 0 deletions ui/store/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5626,6 +5626,10 @@ export function setShowNftAutodetectModal(value: boolean) {
return setPreference('showNftAutodetectModal', value);
}

export function setConfirmationAdvancedDetailsOpen(value: boolean) {
return setPreference('isConfirmationAdvancedDetailsOpen', value);
}

export async function getNextAvailableAccountName(): Promise<string> {
return await submitRequestToBackground<string>(
'getNextAvailableAccountName',
Expand Down

0 comments on commit 05e03d0

Please sign in to comment.