Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions app/_locales/en_GB/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added app/images/money.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,63 @@ describe('TransactionPayControllerInit', () => {
expect(config).toEqual({ accountOverride });
});
});

describe('api.setTransactionPayPaymentOverride', () => {
function initApi() {
const { api, messengerClient } =
TransactionPayControllerInit(getInitRequestMock());
if (!api) {
throw new Error('Expected init result to expose an api');
}
const setTransactionConfigMock = jest.mocked(
messengerClient.setTransactionConfig,
);
return { api, setTransactionConfigMock };
}

it('writes paymentOverride and refundTo', () => {
const { api, setTransactionConfigMock } = initApi();
const refundTo = '0xabcdef1234567890abcdef1234567890abcdef12' as const;

api.setTransactionPayPaymentOverride('tx-1', {
paymentOverride: 'moneyAccount' as never,
refundTo,
});

const updater = setTransactionConfigMock.mock.calls[0][1];
const config: {
paymentOverride?: string;
refundTo?: string;
} = {};
updater(config as never);

expect(config).toEqual({
paymentOverride: 'moneyAccount',
refundTo,
});
});

it('clears paymentOverride and refundTo when override is undefined', () => {
const { api, setTransactionConfigMock } = initApi();

api.setTransactionPayPaymentOverride('tx-2', {
paymentOverride: undefined,
});

const updater = setTransactionConfigMock.mock.calls[0][1];
const config: {
paymentOverride?: string;
refundTo?: string;
} = {
paymentOverride: 'moneyAccount',
refundTo: '0xabc',
};
updater(config as never);

expect(config).toEqual({
paymentOverride: undefined,
refundTo: undefined,
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
PaymentOverride,
TransactionPayController,
TransactionPayControllerMessenger,
TransactionPayStrategy,
Expand Down Expand Up @@ -75,6 +76,27 @@ function getApi(
config.accountOverride = accountOverride;
});
},
setTransactionPayPaymentOverride: (
transactionId: string,
{
paymentOverride,
refundTo,
}: {
paymentOverride?: PaymentOverride;
refundTo?: Hex;
} = {},
) => {
messengerClient.setTransactionConfig(transactionId, (config) => {
config.paymentOverride = paymentOverride;
if (paymentOverride === undefined) {
config.refundTo = undefined;
return;
}
if (refundTo !== undefined) {
config.refundTo = refundTo;
}
});
},
updateTransactionPaymentToken:
messengerClient.updatePaymentToken.bind(messengerClient),
};
Expand Down
8 changes: 8 additions & 0 deletions test/e2e/feature-flags/feature-flag-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,10 @@ export const FEATURE_FLAG_REGISTRY: Record<string, FeatureFlagRegistryEntry> = {
},
},
},
enableMoneyAccountTransactions: {
perpsDeposit: false,
perpsWithdraw: false,
},
},
},
{
Expand All @@ -1188,6 +1192,10 @@ export const FEATURE_FLAG_REGISTRY: Record<string, FeatureFlagRegistryEntry> = {
},
},
},
enableMoneyAccountTransactions: {
perpsDeposit: false,
perpsWithdraw: false,
},
},
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,21 @@ import {
addToken,
findNetworkClientIdByChainId,
} from '../../../../../store/actions';
import { selectIsMoneyAccountTransactionEnabled } from '../../../selectors/feature-flags';
import { usePayWithSections } from '../../../hooks/pay/usePayWithSections';
import { PayWithModal } from './pay-with-modal';

jest.mock('../../../hooks/pay/useTransactionPayToken');
jest.mock('../../../hooks/pay/useTransactionPayData');
jest.mock('../../../hooks/pay/useTransactionPayBlockedTokens');
jest.mock('../../../hooks/pay/useWithdrawTokenFilter');
jest.mock('../../../hooks/pay/usePayWithSections');
jest.mock('../../../utils/transaction-pay');
jest.mock('../../../../../hooks/musd');
jest.mock('../../../selectors/feature-flags', () => ({
...jest.requireActual('../../../selectors/feature-flags'),
selectIsMoneyAccountTransactionEnabled: jest.fn(),
}));
jest.mock('../../../context/confirm', () => ({
useConfirmContext: jest.fn(),
}));
Expand Down Expand Up @@ -124,13 +131,19 @@ describe('PayWithModal', () => {
const usePostQuoteWithdrawTokenFilterMock = jest.mocked(
usePostQuoteWithdrawTokenFilter,
);
const selectIsMoneyAccountTransactionEnabledMock = jest.mocked(
selectIsMoneyAccountTransactionEnabled,
);
const usePayWithSectionsMock = jest.mocked(usePayWithSections);

beforeEach(() => {
jest.resetAllMocks();

useConfirmContextMock.mockReturnValue({
currentConfirmation: {},
} as ReturnType<typeof useConfirmContext>);
selectIsMoneyAccountTransactionEnabledMock.mockReturnValue(false);
usePayWithSectionsMock.mockReturnValue({ sections: [] });

getAvailableTokensMock.mockImplementation(({ tokens }) => tokens as never);
useTransactionPayBlockedTokensMock.mockReturnValue({
Expand Down Expand Up @@ -387,4 +400,101 @@ describe('PayWithModal', () => {
consoleErrorSpy.mockRestore();
});
});

describe('money account pay sections', () => {
beforeEach(() => {
selectIsMoneyAccountTransactionEnabledMock.mockReturnValue(true);
useConfirmContextMock.mockReturnValue({
currentConfirmation: {
type: TransactionType.perpsDeposit,
},
} as ReturnType<typeof useConfirmContext>);
usePayWithSectionsMock.mockReturnValue({
sections: [
{
id: 'money-account',
title: '',
testId: 'pay-with-section-money-account',
rows: [
{
id: 'money-account-musd',
icon: <span />,
title: 'Money account',
subtitle: '$7.05 available',
testId: 'pay-with-money-account-row',
},
],
},
{
id: 'crypto',
title: 'Crypto',
testId: 'pay-with-section-crypto',
rows: [
{
id: 'crypto-other-assets',
icon: <span />,
title: 'Other assets',
subtitle: 'Select from your tokens',
trailingElement: 'chevron',
onPress: jest.fn(),
testId: 'pay-with-crypto-section-other-assets-row',
},
],
},
],
});
});

it('renders sectioned pay options when money account transactions are enabled', () => {
renderModal({ isOpen: true, onClose: onCloseMock });

expect(screen.getByTestId('pay-with-sections')).toBeInTheDocument();
expect(
screen.getByTestId('pay-with-money-account-row'),
).toBeInTheDocument();
expect(
screen.getByText(messages.payWithMoneyAccount.message),
).toBeInTheDocument();
expect(screen.queryByTestId('asset-component')).not.toBeInTheDocument();
});

it('keeps the token asset picker when money account transactions are disabled', () => {
selectIsMoneyAccountTransactionEnabledMock.mockReturnValue(false);

renderModal({ isOpen: true, onClose: onCloseMock });

expect(screen.getByTestId('asset-component')).toBeInTheDocument();
expect(screen.queryByTestId('pay-with-sections')).not.toBeInTheDocument();
});

it('switches to the asset picker when Other assets is pressed', () => {
usePayWithSectionsMock.mockImplementation(({ onOtherAssetsPress }) => ({
sections: [
{
id: 'crypto',
title: 'Crypto',
testId: 'pay-with-section-crypto',
rows: [
{
id: 'crypto-other-assets',
icon: <span />,
title: 'Other assets',
onPress: () => onOtherAssetsPress(),
testId: 'pay-with-crypto-section-other-assets-row',
},
],
},
],
}));

renderModal({ isOpen: true, onClose: onCloseMock });

fireEvent.click(
screen.getByTestId('pay-with-crypto-section-other-assets-row'),
);

expect(screen.getByTestId('asset-component')).toBeInTheDocument();
expect(screen.queryByTestId('pay-with-sections')).not.toBeInTheDocument();
});
});
});
Loading
Loading