Skip to content

feat(multichain-connect-ui): Add UI preparation changes for multichain connection flow #30164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Feb 24, 2025
Merged
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
5 changes: 4 additions & 1 deletion app/_locales/en/messages.json

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

5 changes: 4 additions & 1 deletion app/_locales/en_GB/messages.json

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

17 changes: 17 additions & 0 deletions test/e2e/json-rpc/switchEthereumChain.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ describe('Switch Ethereum Chain for two dapps', function () {
await driver.clickElement('#connectButton');

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

await editButtons[1].click();
Expand Down Expand Up @@ -263,6 +269,12 @@ describe('Switch Ethereum Chain for two dapps', function () {
await driver.clickElement('#connectButton');

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

// Click the edit button for networks
Expand Down Expand Up @@ -383,6 +395,11 @@ describe('Switch Ethereum Chain for two dapps', function () {

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

// Click the edit button for networks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class ConnectAccountConfirmation {
};

private readonly connectAccountConfirmationTitle = {
text: 'Connect with MetaMask',
tag: 'h2',
text: 'Connect this website with MetaMask.',
tag: 'p',
};

constructor(driver: Driver) {
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/page-objects/pages/test-dapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class TestDapp {
private readonly connectAccountButton = '#connectButton';

private readonly connectMetaMaskMessage = {
text: 'Connect with MetaMask',
tag: 'h2',
text: 'Connect this website with MetaMask.',
tag: 'p',
};

private readonly connectedAccount = '#accounts';
Expand Down
10 changes: 10 additions & 0 deletions test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ describe('Request Queuing Dapp 1, Switch Tx -> Dapp 2 Send Tx', function () {

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

await editButtons[1].click();
Expand Down Expand Up @@ -208,6 +213,11 @@ describe('Request Queuing Dapp 1, Switch Tx -> Dapp 2 Send Tx', function () {
await driver.clickElement('#connectButton');

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

await editButtons[1].click();
Expand Down
6 changes: 6 additions & 0 deletions test/e2e/tests/request-queuing/switchChain-watchAsset.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ describe('Request Queue SwitchChain -> WatchAsset', function () {
await driver.clickElement('#connectButton');

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

await editButtons[1].click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ export const SiteCell: React.FC<SiteCellProps> = ({
category: MetaMetricsEventCategory.Navigation,
event: MetaMetricsEventName.ViewPermissionedAccounts,
properties: {
location: 'Connect view, Permissions toast, Permissions (dapp)',
location:
'Connect view (permissions tab), Permissions toast, Permissions (dapp)',
},
});
};
Expand All @@ -112,7 +113,8 @@ export const SiteCell: React.FC<SiteCellProps> = ({
category: MetaMetricsEventCategory.Navigation,
event: MetaMetricsEventName.ViewPermissionedNetworks,
properties: {
location: 'Connect view, Permissions toast, Permissions (dapp)',
location:
'Connect view (permissions tab), Permissions toast, Permissions (dapp)',
},
});
};
Expand Down
1 change: 1 addition & 0 deletions ui/components/ui/tabs/tab/tab.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Tab.propTypes = {
tabIndex: PropTypes.number, // required, but added using React.cloneElement
children: PropTypes.node, // required, but we are not rendering it explicitly
textProps: PropTypes.object, // props to spread to the Text component
width: PropTypes.string,
};

Tab.defaultProps = {
Expand Down
43 changes: 43 additions & 0 deletions ui/helpers/utils/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,49 @@ export const getAvatarFallbackLetter = (subjectName) => {
return subjectName?.match(/[a-z0-9]/iu)?.[0] ?? '?';
};

/**
* Check whether raw origin URL is an IP address.
*
* Note: IPv6 addresses are expected to be wrapped in brackets (e.g. [fe80::1])
* because of how URL formatting works.
*
* @param {string} rawOriginUrl - Raw origin (URL) with protocol that is potentially an IP address
* @returns Boolean, true if the origin is an IP address, false otherwise.
*/
export const isIpAddress = (rawOriginUrl) => {
if (typeof rawOriginUrl === 'string') {
return Boolean(
rawOriginUrl.match(/^(\d{1,3}\.){3}\d{1,3}$|^\[[0-9a-f:]+\]$/iu),
);
}

return false;
};

/**
* Transforms full raw URLs to something that can be used as title.
* Basically, it removes subdomain and protocol prefixes.
*
* Note: For IP address origins, full IP address without protocol will be returned.
*
* @param {string} rawOrigin - Raw origin (URL) with protocol.
* @returns User friendly title extracted from raw URL.
*/
export const transformOriginToTitle = (rawOrigin) => {
try {
const url = new URL(rawOrigin);

if (isIpAddress(url.hostname)) {
return url.hostname;
}

const parts = url.hostname.split('.');
return parts.slice(-2).join('.');
} catch (e) {
return 'Unknown Origin';
}
};

/**
* Get abstracted Snap permissions filtered by weight.
*
Expand Down
50 changes: 50 additions & 0 deletions ui/helpers/utils/util.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1298,4 +1298,54 @@ describe('util', () => {
expect(sortedAccount).toStrictEqual([]);
});
});

describe('isIpAddress', () => {
it('should return true for the IPv4 address', () => {
expect(util.isIpAddress('127.0.0.1')).toBe(true);
});

it('should return true for the IPv6 address', () => {
expect(util.isIpAddress('[fe80::1]')).toBe(true);
});

it('should return true for the invalid IP address', () => {
expect(util.isIpAddress('metamask')).toBe(false);
});

it('should return true for the invalid type of argument', () => {
expect(util.isIpAddress(1024)).toBe(false);
});
});

describe('transformOriginToTitle', () => {
it('should return the correct title for origin with domain', () => {
expect(util.transformOriginToTitle('https://metamask.io')).toBe(
'metamask.io',
);
});

it('should return the correct title for origin with subdomain', () => {
expect(
util.transformOriginToTitle('https://metamask.github.io/test-dapp/'),
).toBe('github.io');
});

it('should return the correct title for localhost', () => {
expect(util.transformOriginToTitle('http://localhost:3000')).toBe(
'localhost',
);
});

it('should return the correct title for IPv4 address', () => {
expect(util.transformOriginToTitle('http://127.0.0.1:3000')).toBe(
'127.0.0.1',
);
});

it('should return the correct title for IPv6 address', () => {
expect(util.transformOriginToTitle('http://[fe80::1]:9011/')).toBe(
'[fe80::1]',
);
});
});
});
Loading
Loading