Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8faf9bb
feat: only use remote FF for sidepanel
NidhiKJha Nov 28, 2025
a41e775
lint fix
NidhiKJha Nov 28, 2025
29dcfa1
restored check for firefox
NidhiKJha Nov 28, 2025
41ee047
updated manifest
NidhiKJha Nov 28, 2025
bcf1659
Merge branch 'main' into sidepanel-remote-flag
NidhiKJha Nov 28, 2025
97231f5
updated test
NidhiKJha Dec 1, 2025
f00030e
Merge branch 'main' into sidepanel-remote-flag
NidhiKJha Dec 1, 2025
5f662b7
updated console error
NidhiKJha Dec 1, 2025
733a22b
e2e fix
NidhiKJha Dec 1, 2025
e3f10e8
updated helpers
NidhiKJha Dec 1, 2025
faf9891
updated helpers
NidhiKJha Dec 1, 2025
d390cd2
Merge branch 'main' into sidepanel-remote-flag
NidhiKJha Dec 1, 2025
8c865ce
helper update
NidhiKJha Dec 1, 2025
cd6e517
updated sidepanel
NidhiKJha Dec 1, 2025
956cadb
updated sidepanel
NidhiKJha Dec 1, 2025
3e29061
Merge branch 'main' into sidepanel-remote-flag
NidhiKJha Dec 1, 2025
a4980cb
sidepanel fence
NidhiKJha Dec 1, 2025
c286e1e
Merge branch 'main' into sidepanel-remote-flag
ameliejyc Dec 2, 2025
fa9d999
fix: e2e tests by adding sidepanel env flag
ameliejyc Dec 2, 2025
920ea47
chore: update sidepanel env check conditions
ameliejyc Dec 2, 2025
e692d9a
chore: fix isSidePanelEnabled calls
ameliejyc Dec 2, 2025
056ccbf
chore: fix isSidePanelEnabled calls again
ameliejyc Dec 2, 2025
f78abd4
chore: bring back useSidePanelEnabled
ameliejyc Dec 2, 2025
67c4541
fix: onboarding e2e tests
ameliejyc Dec 2, 2025
b14a9d5
chore: add debug log
ameliejyc Dec 2, 2025
11255c1
fix: Browser import
ameliejyc Dec 2, 2025
2fa16aa
chore: make hasSidepanel check more specific
ameliejyc Dec 2, 2025
bb8b7e3
chore: fix lint
ameliejyc Dec 2, 2025
6f558d9
Merge branch 'main' into sidepanel-remote-flag
ameliejyc Dec 2, 2025
4916d85
fix: problematic browser import
ameliejyc Dec 2, 2025
346dad3
fix: vault encryptor test
ameliejyc Dec 2, 2025
23c0f5d
Merge branch 'main' into sidepanel-remote-flag
hjetpoluru Dec 2, 2025
4b50616
chore: revert back isSidePanelEnabled code
ameliejyc Dec 2, 2025
cab7484
chore: remove unused import
ameliejyc Dec 2, 2025
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
3 changes: 1 addition & 2 deletions app/manifest/v3/_base.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@
"webRequest",
"offscreen",
"identity",
"sidePanel",
"contextMenus"
"sidePanel"
],
"sandbox": {
"pages": ["snaps/index.html"]
Expand Down
23 changes: 0 additions & 23 deletions app/scripts/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ import {
CorruptionHandler,
hasVault,
} from './lib/state-corruption/state-corruption-recovery';
import { initSidePanelContextMenu } from './lib/sidepanel-context-menu';
import {
backedUpStateKeys,
PersistenceManager,
Expand Down Expand Up @@ -183,7 +182,6 @@ const PHISHING_WARNING_PAGE_TIMEOUT = ONE_SECOND_IN_MILLISECONDS;

lazyListener.once('runtime', 'onInstalled').then((details) => {
handleOnInstalled(details);
handleSidePanelContextMenu();
});

/**
Expand Down Expand Up @@ -1663,15 +1661,6 @@ function onInstall() {
}
}

/**
* Handles the onInstalled event for sidepanel context menu creation.
* This is registered via lazyListener to catch the event at module load time.
*/
async function handleSidePanelContextMenu() {
await isInitialized;
await initSidePanelContextMenu(controller);
}

/**
* Trigger actions that should happen only when an update is available
*/
Expand Down Expand Up @@ -1749,18 +1738,6 @@ const initSidePanelBehavior = async () => {
openPanelOnActionClick: useSidePanelAsDefault,
});
}

// Setup remote feature flag listener to update sidepanel preferences
controller?.controllerMessenger?.subscribe(
'RemoteFeatureFlagController:stateChange',
(state) => {
const extensionUxSidepanel =
state?.remoteFeatureFlags?.extensionUxSidepanel;
if (extensionUxSidepanel === false) {
controller?.preferencesController?.setUseSidePanelAsDefault(false);
}
},
);
} catch (error) {
console.error('Error setting side panel behavior:', error);
}
Expand Down
63 changes: 0 additions & 63 deletions app/scripts/lib/sidepanel-context-menu.ts

This file was deleted.

5 changes: 3 additions & 2 deletions builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ buildTypes:
- REJECT_INVALID_SNAPS_PLATFORM_VERSION: true
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/10.2.3/index.html
- ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management
- IS_SIDEPANEL: false
- IS_SIDEPANEL: true
- EXTENSION_UX_PNA25: true
# for seedless onboarding (social login)
- GOOGLE_BETA_CLIENT_ID
Expand Down Expand Up @@ -140,7 +140,7 @@ buildTypes:
- SEGMENT_WRITE_KEY_REF: SEGMENT_FLASK_WRITE_KEY
- ACCOUNT_SNAPS_DIRECTORY_URL: https://metamask.github.io/snaps-directory-staging/main/account-management
- EIP_4337_ENTRYPOINT: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'
- IS_SIDEPANEL: false
- IS_SIDEPANEL: true
- EXTENSION_UX_PNA25: true
# for seedless onboarding (social login)
- GOOGLE_FLASK_CLIENT_ID
Expand Down Expand Up @@ -467,3 +467,4 @@ env:

# PNA25 (Privacy Notice)
- EXTENSION_UX_PNA25: true
- IS_SIDEPANEL: true
12 changes: 12 additions & 0 deletions test/e2e/dist/vault-decryption-chrome.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ describe('Vault Decryptor Page', function () {
await withFixtures(
{
disableServerMochaToBackground: true,
ignoredConsoleErrors: ['GL Context was lost'],
title: this.test?.fullTitle(),
},
async ({ driver }) => {
Expand All @@ -190,6 +191,11 @@ describe('Vault Decryptor Page', function () {
// close popover if any (Announcements etc..)
await closePopoverIfPresent(driver);

// Ensure we're on the main extension window after onboarding
await driver.switchToWindowWithTitle(
WINDOW_TITLES.ExtensionInFullScreenView,
);

// go to privacy settings page
const homePage = new HomePage(driver);
await homePage.checkPageIsLoaded();
Expand Down Expand Up @@ -234,6 +240,7 @@ describe('Vault Decryptor Page', function () {
await withFixtures(
{
disableServerMochaToBackground: true,
ignoredConsoleErrors: ['GL Context was lost'],
title: this.test?.fullTitle(),
},
async ({ driver }) => {
Expand All @@ -253,6 +260,11 @@ describe('Vault Decryptor Page', function () {
// close popover if any (Announcements etc..)
await closePopoverIfPresent(driver);

// Ensure we're on the main extension window after onboarding
await driver.switchToWindowWithTitle(
WINDOW_TITLES.ExtensionInFullScreenView,
);

// go to privacy settings page
const homePage = new HomePage(driver);
await homePage.checkPageIsLoaded();
Expand Down
34 changes: 34 additions & 0 deletions test/e2e/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,39 @@ async function initBundler(

const sentryRegEx = /^https:\/\/sentry\.io\/api\/\d+\/envelope/gu;

/**
* Check if sidepanel is enabled by examining the manifest at runtime.
* Only works on Chrome-based browsers (Firefox doesn't support sidepanel).
*
* @param {Driver} driver - The WebDriver instance
* @returns {Promise<boolean>} True if sidepanel permission is present in manifest
*/
async function isSidePanelEnabled(driver) {
try {
const manifest = await driver.executeScript(`
try {
if (typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.getManifest) {
return chrome.runtime.getManifest();
}
return null;
} catch (e) {
return null;
}
`);

const hasSidepanel = Boolean(manifest?.permissions?.includes('sidePanel'));

// Log for debugging
console.log(`Sidepanel check: ${hasSidepanel ? 'enabled' : 'disabled'}`);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sidepanel will only be enabled if we have sidepanel permissions in manifest

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmm and when will this happen?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is to ensure sidepanel is rendered based on remote FF: IS_SIDEPANEL`

I'm trying to understand the behaviour of the PR and it's not totally clear to me 🤔

If the side panel will be enabled using a remote FF (launcharkly), then, why don't we mock the FF response, in the cases where we want to enable/disable? Why do we need this function at all, if we can know on each test if it's enabled/disabled

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Mariona, I'm working on this whilst Nidhi is out.

It will only use a build flag, not a feature flag. I think the idea is that we keep this helper in the tests so that if for any reason we do need to switch off the flag in builds.yml, we also have an easy way of making sure the tests still pass. Note, we are planning to add IS_SIDEPANEL: true flag into run-e2e.yml also to fix the vault encryption tests. This means we'll check that flag in this helper instead. So if sidepanel has to be turned off, we would set the build flag and the e2e flag values to false, and then the e2e tests will still work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for your reply @ameliejyc 🙏

It will only use a build flag, not a feature flag.

mmm this seems to be conflicting with the PR title which states:

only use remote FF for sidepanel

Am I missing something here? 🤔

As per the hasSidepanel, I think having a check like this in the tests can be a bit problematic, as then it's really hard to tell if that test is using sidepanel or not, just by looking at the test.

WE'll for sure need to use the process.env.SELENIUM_BROWSER for the case it's Chrome and it's enabled -- but we should know if it's enabled or not, and see it easily in the spec.

Does it make sense? Could this be re-thought?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmm this seems to be conflicting with the PR title which states:

Great point, also updated!

As per the hasSidepanel, I think having a check like this in the tests can be a bit problematic, as then it's really hard to tell if that test is using sidepanel or not, just by looking at the test.

@seaona I totally see your point. I think the idea is that this build flag is removed as soon as possible once sidepanel is released and working well in production. At that point we would assume that sidepanel is just a normal feature of the wallet and expect it to be there in all the tests, and we could then remove the build flag completely and the associated checks. I think the check right now is really just in case there's an emergency situation where the flag should be turned to false whilst we are releasing it. @hesterbruikman would probably be able to share more as I am probably missing a bit of the conversation on this over the past couple of weeks.


return hasSidepanel;
} catch (error) {
// Chrome API not accessible (e.g., LavaMoat scuttling mode, Firefox)
console.log('Sidepanel check failed:', error.message);
return false;
}
}

module.exports = {
DAPP_HOST_ADDRESS,
DAPP_URL,
Expand Down Expand Up @@ -833,4 +866,5 @@ module.exports = {
clickNestedButton,
sentryRegEx,
createWebSocketConnection,
isSidePanelEnabled,
};
62 changes: 43 additions & 19 deletions test/e2e/page-objects/flows/onboarding.flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,63 @@ import StartOnboardingPage from '../pages/onboarding/start-onboarding-page';
import SecureWalletPage from '../pages/onboarding/secure-wallet-page';
import OnboardingCompletePage from '../pages/onboarding/onboarding-complete-page';
import OnboardingPrivacySettingsPage from '../pages/onboarding/onboarding-privacy-settings-page';
import { WALLET_PASSWORD } from '../../helpers';
import { WALLET_PASSWORD, isSidePanelEnabled } from '../../helpers';
import { E2E_SRP } from '../../fixtures/default-fixture';
import HomePage from '../pages/home/homepage';
import LoginPage from '../pages/login-page';
import TermsOfUseUpdateModal from '../pages/dialog/terms-of-use-update-modal';

/**
* Helper function to handle post-onboarding navigation for sidepanel builds.
* When sidepanel is enabled, clicking "Done" doesn't navigate the current window,
* so we need to manually navigate to home.html.
* When sidepanel is enabled, clicking "Done" opens the home page in the sidepanel,
* but the main window remains on the onboarding completion page.
* This function navigates the current window to the actual home page.
* Note: Sidepanel is only supported on Chrome-based browsers, not Firefox.
*
* @param driver - The WebDriver instance
*/
export const handleSidepanelPostOnboarding = async (
driver: Driver,
): Promise<void> => {
// Check if sidepanel is enabled via build configuration
// AND we're not running on Firefox (which doesn't support sidepanel)
const isSidepanelEnabled =
process.env.IS_SIDEPANEL === 'true' &&
process.env.SELENIUM_BROWSER !== Browser.FIREFOX;

if (isSidepanelEnabled) {
// Give the onboarding completion time to process (needed for sidepanel)
await driver.delay(2000);

// Navigate directly to home page in current window
// With sidepanel enabled, this ensures we load home page in the test window
await driver.driver.get(`${driver.extensionUrl}/home.html`);

// Wait for the home page to fully load
await driver.waitForSelector('[data-testid="account-menu-icon"]');
// Only run on Chrome-based browsers (Firefox doesn't support sidepanel)
if (process.env.SELENIUM_BROWSER === Browser.FIREFOX) {
return;
}

try {
const hasSidepanel = await isSidePanelEnabled(driver);

// Skip if sidepanel is not enabled
if (!hasSidepanel) {
return;
}

const currentUrl = await driver.getCurrentUrl();

// Only navigate if still on the completion page
// Avoid duplicate navigation if already on home page
if (currentUrl.includes('#onboarding/completion')) {
await driver.driver.get(`${driver.extensionUrl}/home.html`);
} else if (currentUrl.includes('/home.html')) {
// Already on home page, skip navigation
return;
} else {
await driver.driver.get(`${driver.extensionUrl}/home.html`);
}

// Wait for home page to be ready
await driver.waitForMultipleSelectors([
'[data-testid="eth-overview-send"]', // send button
'[data-testid="account-overview__activity-tab"]', // activity tab
'[data-testid="account-overview__asset-tab"]', // tokens tab
]);
} catch (error) {
// If sidepanel handling fails, continue without it
// The test may still work if the main window navigated correctly
console.log(
'Sidepanel handling skipped or failed:',
error instanceof Error ? error.message : String(error),
);
}
};

Expand Down
Loading
Loading