Skip to content

Commit

Permalink
test(e2e): Solana Phantom Wallet (#433)
Browse files Browse the repository at this point in the history
  • Loading branch information
nelitow authored Nov 28, 2024
1 parent 5e3d8fc commit 9cf640d
Show file tree
Hide file tree
Showing 10 changed files with 3,848 additions and 134 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
expect,
getButtonByText,
getByAriaLabel,
} from '@fuels/playwright-utils';
import type { Page } from '@playwright/test';
import phantom from '../../../node_modules/@phantom/synpress/commands/phantom';
import { test } from './setup';

phantom.confirmTransaction = async () => {
const notificationPage =
await phantom.playwright.switchToNotification('phantom');
await phantom.playwright.waitAndClick(
'phantom',
phantom.transactionPageElements.buttons.confirmTransaction, // Ensure this locator exists or define it
notificationPage,
{ waitForEvent: 'close' },
);
return true;
};

test.describe('SolanaConnector', () => {
test.slow();

const connect = async (page: Page) => {
await page.goto('/');
const connectButton = getButtonByText(page, 'Connect Wallet', true);
await connectButton.click();
await getByAriaLabel(page, 'Connect to Solana Wallets', true).click();
await page.getByText('Proceed anyway').click();
await getButtonByText(page, 'Phantom').click();
await phantom.acceptAccess();
await page.waitForTimeout(3000);
};

test('Fuel tests', async ({ page }) => {
await connect(page);
const addressElement = await page.locator('#address');
let address = null;
if (addressElement) {
address = await addressElement.getAttribute('data-address');
}
test.step('Check if address is not null', () => {
expect(address).not.toBeNull();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const PHANTOM_CONFIG = {
MNEMONIC: 'test test test test test test test test test test test junk',
WALLET_PASSWORD: 'Tester@1234',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './setup';
export * from './config';
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { BrowserContext } from '@playwright/test';
import { chromium } from '@playwright/test';
import phantomCommands from '../../../../node_modules/@phantom/synpress/commands/phantom';
import phantomHelpers from '../../../../node_modules/@phantom/synpress/helpers';
import { PHANTOM_CONFIG } from './config';

export async function phantomPath() {
return await phantomHelpers.prepareProvider('phantom', 'latest');
}
export async function setupPhantom(_context: BrowserContext) {
await phantomCommands.initialSetup(chromium, {
secretWordsOrPrivateKey: PHANTOM_CONFIG.MNEMONIC,
network: 'localhost',
password: PHANTOM_CONFIG.WALLET_PASSWORD,
enableAdvancedSettings: true,
enableExperimentalSettings: false,
});
}
37 changes: 37 additions & 0 deletions e2e-tests/runner/examples/connectors/SolanaConnector/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { BrowserContext } from '@playwright/test';
import { test as base, chromium } from '@playwright/test';
import { phantomPath, setupPhantom } from './phantom';

import { getExtensionsData } from './utils/getExtensionsData';
import { waitForExtensions } from './utils/waitForExtensions';

export const test = base.extend<{
context: BrowserContext;
extensionId: string;
}>({
context: async ({ context: _ }, use) => {
global.expect = expect;
const path = await phantomPath();
const browserArgs = [
`--disable-extensions-except=${path}`,
`--load-extension=${path}`,
'--remote-debugging-port=9222',
];
const context = await chromium.launchPersistentContext('', {
headless: false,
args: browserArgs,
});
const extensions = await getExtensionsData(context);
await waitForExtensions(context, extensions);
await setupPhantom();
await use(context);
},
extensionId: async ({ context }, use) => {
let [background] = context.serviceWorkers();
if (!background) background = await context.waitForEvent('serviceworker');
const extensionId = background.url().split('/')[2];
await use(extensionId);
},
});

export const expect = test.expect;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* This code is required to avoid synpress to start without
* the extensions be ready making it fail.
*
* This code was copied from the synpress codebase to be used as a standalone function.
* https://github.com/Synthetixio/synpress/blob/81faa920fb683b1b579fde5214f923c758877157/commands/playwright.js#L445
*/

import type { BrowserContext } from '@playwright/test';

export async function getExtensionsData(context: BrowserContext) {
const extensionsData = {};
const page = await context.newPage();

await page.goto('chrome://extensions');
await page.waitForLoadState('load');
await page.waitForLoadState('domcontentloaded');

const devModeButton = page.locator('#devMode');
await devModeButton.waitFor();
await devModeButton.focus();
await devModeButton.click();

const extensionDataItems = await page.locator('extensions-item').all();
for (const extensionData of extensionDataItems) {
const extensionName = (
await extensionData
.locator('#name-and-version')
.locator('#name')
.textContent()
).toLowerCase();

const extensionVersion = (
await extensionData
.locator('#name-and-version')
.locator('#version')
.textContent()
).replace(/(\n| )/g, '');

const extensionId = (
await extensionData.locator('#extension-id').textContent()
).replace('ID: ', '');

extensionsData[extensionName] = {
version: extensionVersion,
id: extensionId,
};
}
await page.close();

return extensionsData;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { setTimeout } from 'node:timers/promises';
import type { BrowserContext } from '@playwright/test';

export async function waitForExtensions(
context: BrowserContext,
extensions: Record<
string,
{
id: string;
version: string;
}
>,
maxAttempts = 5,
attempt = 0,
): Promise<boolean> {
if (!context) throw new Error('BrowserContext is required.');
if (!extensions || typeof extensions !== 'object') {
throw new Error('Invalid extensions object provided.');
}
console.log(`Checking extensions (Attempt ${attempt + 1}/${maxAttempts})...`);
const pages = context.pages();
if (!pages.length) {
console.warn('No pages found in the context. Retrying...');
}
const phantomPage = pages.find((page) =>
page.url().includes(extensions.phantom?.id),
);
if (phantomPage) {
console.log('Phantom extension is ready!');
return true;
}
if (attempt >= maxAttempts - 1) {
throw new Error(
`Failed to detect extensions after ${maxAttempts} attempts.`,
);
}
console.log('Phantom extension not found. Retrying in 3 seconds...');
await setTimeout(3000);
return waitForExtensions(context, extensions, maxAttempts, attempt + 1);
}
5 changes: 5 additions & 0 deletions e2e-tests/runner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
"scripts": {
"test:e2e": "pnpm run start:servers & pnpm exec playwright test",
"test:e2e:ui": "playwright test --ui --debug",
"test:react-app": "pnpm test:react-app:ci -- --ui",
"test:react-app:ci": "playwright test e2e-tests/react-app --project=react-app",
"test:react-next": "pnpm playwright test --project=react-next",
"test:e2e:dev": "pnpm --workspace-root node:up && pnpm run start:servers & pnpm playwright test --ui",
"test:e2e:local": "pnpm run deploy:contracts && pnpm run test:e2e",
"start:react-app": "pnpm --filter react-app dev",
"start:react-next": "pnpm --filter @e2e-tests/react-next dev",
Expand All @@ -23,6 +27,7 @@
"@synthetixio/synpress": "4.0.3",
"@synthetixio/synpress-cache": "0.0.4",
"dotenv": "16.4.5",
"@phantom/synpress": "4.0.0-alpha.53",
"fuels": "0.96.1"
},
"engines": {
Expand Down
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,5 @@
"fast-xml-parser@<4.4.1": ">=4.4.1"
}
},
"packageManager": "[email protected]",
"dependencies": {
"@synthetixio/synpress": "4.0.3"
}
"packageManager": "[email protected]"
}
Loading

0 comments on commit 9cf640d

Please sign in to comment.